Repository navigation
Batch api #461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Batch api #461
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f8ec721
t
91c475c
batch api initial support for list of BoxAPIRequests
2cf6632
making it more user friendly and better exception handling
8867f0b
checkstyle
ff07156
batch example and unit tests
947c80b
example details
1f78f14
relative path for suppressing checkstyle. documentation for BatchAPIR…
70de9a6
feedback
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
src/example/java/com/box/sdk/example/BatchRequestExample.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| package com.box.sdk.example; | ||
|
|
||
| import java.io.FileReader; | ||
| import java.io.IOException; | ||
| import java.io.Reader; | ||
| import java.net.URL; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.logging.Level; | ||
| import java.util.logging.Logger; | ||
|
|
||
| import com.box.sdk.BatchAPIRequest; | ||
| import com.box.sdk.BoxAPIRequest; | ||
| import com.box.sdk.BoxAPIResponse; | ||
| import com.box.sdk.BoxConfig; | ||
| import com.box.sdk.BoxDeveloperEditionAPIConnection; | ||
| import com.box.sdk.BoxFolder; | ||
| import com.box.sdk.BoxJSONRequest; | ||
| import com.box.sdk.BoxJSONResponse; | ||
| import com.box.sdk.BoxUser; | ||
| import com.box.sdk.IAccessTokenCache; | ||
| import com.box.sdk.InMemoryLRUAccessTokenCache; | ||
| import com.box.sdk.http.HttpMethod; | ||
|
|
||
| /** | ||
| * | ||
| */ | ||
| public final class BatchRequestExample { | ||
|
|
||
| private static final int MAX_CACHE_ENTRIES = 100; | ||
| private static final String APP_USER_NAME = "BATCH-TEST-APP-USER-NAME"; | ||
|
|
||
| private BatchRequestExample() { } | ||
|
|
||
| public static void main(String[] args) throws IOException { | ||
| // Turn off logging to prevent polluting the output. | ||
| Logger.getLogger("com.box.sdk").setLevel(Level.OFF); | ||
|
|
||
|
|
||
| //It is a best practice to use an access token cache to prevent unneeded requests to Box for access tokens. | ||
| //For production applications it is recommended to use a distributed cache like Memcached or Redis, and to | ||
| //implement IAccessTokenCache to store and retrieve access tokens appropriately for your environment. | ||
| IAccessTokenCache accessTokenCache = new InMemoryLRUAccessTokenCache(MAX_CACHE_ENTRIES); | ||
|
|
||
| Reader reader = new FileReader("src/example/config/config.json"); | ||
| BoxConfig boxConfig = BoxConfig.readFrom(reader); | ||
|
|
||
| BoxDeveloperEditionAPIConnection api = BoxDeveloperEditionAPIConnection.getAppEnterpriseConnection( | ||
| boxConfig, accessTokenCache); | ||
|
|
||
| List<BoxAPIRequest> requests = new ArrayList<BoxAPIRequest>(); | ||
|
|
||
| //Get current user request | ||
| URL getMeURL = BoxUser.GET_ME_URL.build(api.getBaseURL()); | ||
| BoxAPIRequest getMeRequest = new BoxAPIRequest(getMeURL, HttpMethod.GET); | ||
| requests.add(getMeRequest); | ||
|
|
||
| //Create App User Request | ||
| URL createUserURL = BoxUser.USERS_URL_TEMPLATE.build(api.getBaseURL()); | ||
| BoxJSONRequest createAppUserRequest = new BoxJSONRequest(createUserURL, HttpMethod.POST); | ||
| createAppUserRequest.setBody("{\"name\":\"" + APP_USER_NAME + "\",\"is_platform_access_only\":true}"); | ||
| requests.add(createAppUserRequest); | ||
|
|
||
| //Get Root Folder Request | ||
| URL getRootFolderURL = BoxFolder.FOLDER_INFO_URL_TEMPLATE.build(api.getBaseURL(), 0); | ||
| BoxAPIRequest getRootFolderRequest = new BoxAPIRequest(getRootFolderURL, HttpMethod.GET); | ||
| requests.add(getRootFolderRequest); | ||
|
|
||
| BatchAPIRequest batchRequest = new BatchAPIRequest(api); | ||
| List<BoxAPIResponse> responses = batchRequest.execute(requests); | ||
|
|
||
| System.out.println("GET ME RESPONSE:"); | ||
| System.out.println("Response Code: " + responses.get(0).getResponseCode()); | ||
| System.out.println("Response: " + ((BoxJSONResponse) responses.get(1)).getJSON()); | ||
|
|
||
| System.out.println("CREATE APP USER RESPONSE:"); | ||
| System.out.println("Response Code: " + responses.get(1).getResponseCode()); | ||
| System.out.println("Response: " + ((BoxJSONResponse) responses.get(1)).getJSON()); | ||
|
|
||
| System.out.println("GET ROOT FOLDER RESPONSE:"); | ||
| System.out.println("Response Code: " + responses.get(2).getResponseCode()); | ||
| BoxJSONResponse rootFolderResponse = (BoxJSONResponse) responses.get(1); | ||
| BoxFolder.Info rootFolderInfo = new BoxFolder(api, rootFolderResponse.getJsonObject().get("id").asString()) | ||
| .new Info(rootFolderResponse.getJsonObject()); | ||
| System.out.println("Root Folder Created At: " + rootFolderInfo.getCreatedAt()); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| package com.box.sdk; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.Iterator; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| import com.box.sdk.http.HttpHeaders; | ||
| import com.box.sdk.http.HttpMethod; | ||
| import com.eclipsesource.json.JsonArray; | ||
| import com.eclipsesource.json.JsonObject; | ||
| import com.eclipsesource.json.JsonValue; | ||
|
|
||
| /** | ||
| * Used to make a bunch of HTTP Requests as a batch. Currently the number of requests that can be batched at once | ||
| * is capped at <b>20</b> by the API layer. Also there are certain requests which <b>cannot</b> be performed | ||
| * by Batch API. Check API documentation for more information. | ||
| * | ||
| * <p>The request itself is a BoxJSONRequest but extends it to provide additional functionality for aggregating | ||
| * a bunch of requests and responding with multiple responses as if the requests were called individually</p> | ||
| */ | ||
| public class BatchAPIRequest extends BoxJSONRequest { | ||
| /** | ||
| * Batch URL Template. | ||
| */ | ||
| public static final URLTemplate BATCH_URL_TEMPLATE = new URLTemplate("batch"); | ||
| private final BoxAPIConnection api; | ||
|
|
||
| /** | ||
| * Constructs an authenticated BatchRequest using a provided BoxAPIConnection. | ||
| * @param api an API connection for authenticating the request. | ||
| */ | ||
| public BatchAPIRequest(BoxAPIConnection api) { | ||
| super(api, BATCH_URL_TEMPLATE.build(api.getBaseURL()), HttpMethod.GET); | ||
| this.api = api; | ||
| } | ||
|
|
||
| /** | ||
| * Execute a set of API calls as batch request. | ||
| * @param requests list of api requests that has to be executed in batch. | ||
| * @return list of BoxAPIResponses | ||
| */ | ||
| public List<BoxAPIResponse> execute(List<BoxAPIRequest> requests) { | ||
| this.prepareRequest(requests); | ||
| BoxJSONResponse batchResponse = (BoxJSONResponse) send(); | ||
| return this.parseResponse(batchResponse); | ||
| } | ||
|
|
||
| /** | ||
| * Prepare a batch api request using list of individual reuests. | ||
| * @param requests list of api requests that has to be executed in batch. | ||
| */ | ||
| protected void prepareRequest(List<BoxAPIRequest> requests) { | ||
| JsonObject body = new JsonObject(); | ||
| JsonArray requestsJSONArray = new JsonArray(); | ||
| for (BoxAPIRequest request: requests) { | ||
| JsonObject batchRequest = new JsonObject(); | ||
| batchRequest.add("method", request.getMethod()); | ||
| batchRequest.add("relative_url", request.getUrl().toString().substring(this.api.getBaseURL().length() - 1)); | ||
| //If the actual request has a JSON body then add it to vatch request | ||
| if (request instanceof BoxJSONRequest) { | ||
| BoxJSONRequest jsonRequest = (BoxJSONRequest) request; | ||
| batchRequest.add("body", jsonRequest.getBodyAsJsonObject()); | ||
| } | ||
| //Add any headers that are in the request, except Authorization | ||
| if (request.getHeaders() != null) { | ||
| JsonObject batchRequestHeaders = new JsonObject(); | ||
| for (RequestHeader header: request.getHeaders()) { | ||
| if (header.getKey() != null && !header.getKey().isEmpty() | ||
| && HttpHeaders.AUTHORIZATION.equals(header.getKey())) { | ||
| batchRequestHeaders.add(header.getKey(), header.getValue()); | ||
| } | ||
| } | ||
| batchRequest.add("headers", batchRequestHeaders); | ||
| } | ||
|
|
||
| //Add the request to array | ||
| requestsJSONArray.add(batchRequest); | ||
| } | ||
| //Add the requests array to body | ||
| body.add("requests", requestsJSONArray); | ||
| super.setBody(body); | ||
| } | ||
|
|
||
| /** | ||
| * Parses btch api response to create a list of BoxAPIResponse objects. | ||
| * @param batchResponse response of a batch api request | ||
| * @return list of BoxAPIResponses | ||
| */ | ||
| protected List<BoxAPIResponse> parseResponse(BoxJSONResponse batchResponse) { | ||
| JsonObject responseJSON = JsonObject.readFrom(batchResponse.getJSON()); | ||
| List<BoxAPIResponse> responses = new ArrayList<BoxAPIResponse>(); | ||
| Iterator<JsonValue> responseIterator = responseJSON.get("responses").asArray().iterator(); | ||
| while (responseIterator.hasNext()) { | ||
| JsonObject jsonResponse = responseIterator.next().asObject(); | ||
| BoxAPIResponse response = null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible the batch API will throw 500?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Totally. That will be thrown as BoxAPIException |
||
|
|
||
| //Gather headers | ||
| Map<String, String> responseHeaders = new HashMap<String, String>(); | ||
|
|
||
| if (jsonResponse.get("headers") != null) { | ||
| JsonObject batchResponseHeadersObject = jsonResponse.get("headers").asObject(); | ||
| for (JsonObject.Member member : batchResponseHeadersObject) { | ||
| String headerName = member.getName(); | ||
| String headerValue = member.getValue().asString(); | ||
| responseHeaders.put(headerName, headerValue); | ||
| } | ||
| } | ||
|
|
||
| // Construct a BoxAPIResponse when response is null, or a BoxJSONResponse when there's a response | ||
| // (not anticipating any other response as per current APIs. | ||
| // Ideally we should do it based on response header) | ||
| if (jsonResponse.get("response") == null) { | ||
| response = | ||
| new BoxAPIResponse(jsonResponse.get("status").asInt(), responseHeaders); | ||
| } else { | ||
| response = | ||
| new BoxJSONResponse(jsonResponse.get("status").asInt(), responseHeaders, | ||
| jsonResponse.get("response").asObject()); | ||
| } | ||
| responses.add(response); | ||
| } | ||
| return responses; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what will happen if more than 20 request?
What about the non-whitelisted request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API will throw an error. No special handling in the SDK