APIMatic has introduced core libraries to provide a stable runtime that powers all functionality of our SDKs. In this release, we have revamped our Java SDKs to improve the code quality and provide better test coverage.
Refer to Introducing core libraries in APIMatic generated SDKs changelog to understand the importance of core libraries in our SDKs.
Core Libraries
The core libraries consist of classes that are used to make up the Java SDK. They help the SDKs to create and execute requests and responses using the best practices of Java language.
Some of the main features that core libraries introduce in our Java SDKs are:
- Processing of the request
- Request creation
- Execution of the request
- Response handling
- Unit testing
All these features are rigorously tested to guarantee the highest level of speed and stability. To aid this testing, core interfaces are introduced along with core libraries. These libraries include:
Core Interfaces
Core interfaces provide an abstraction later on top of core libraries. This results in a cleaner interface and an abstraction for the core functionality of these classes for our SDK users. Consequently, it enhances the scalability of our Java SDKs.
These core interfaces are discussed below:
HttpClient
- To send HTTP requests and read the responses
HttpClient
interface is an integral part of the client functionality which is implemented byOkClient
CompatibilityFactory
- For backward compatibility
Authentication
- To setup methods for authentication
Method
- Enumeration containing
HttpMethods
- Enumeration containing
Benefits of Core Libraries in Java SDKs
Here are the benefits of introducing core libraries in Java SDKs.
Wrapped Http Client
The OkHttp
client adapter library is used by the Java SDK when sending an HTTP request. Earlier versions of the SDK came with an integrated client implementation for sending HTTP requests using this module. With the addition of core libraries, the implementation of the OkHttp
client has been divided into a separate package and is added to the SDK as a dependency.
Previously, the logger was started in the client but now, it is being injected. The client offers a simple and elegant alternative to the SDK for implementing the same capabilities. We now have client support for unit testing to ensure improved component dependability and performance.
/**
* To send HTTP Requests and read the responses.
*
*/
public interface HttpClient {
/**
* Execute a given Request to get string/binary response back.
*
* @param request The given HttpRequest to execute.
* @param endpointConfiguration The overridden configuration for request.
* @return CompletableFuture of Response after execution.
*/
public CompletableFuture<Response> executeAsync(final Request request,
CoreEndpointConfiguration endpointConfiguration);
/**
* Execute a given Request to get string/binary response back.
*
* @param request The given Request to execute.
* @param retryConfiguration The overridden retry configuration for request.
* @return The converted response.
* @throws IOException exception to be thrown while converting response.
*/
public Response execute(final Request request, CoreEndpointConfiguration endpointConfiguration) throws IOException;
}
Improved SDK
The Java SDK is now lighter in size. All utilities have been moved to the core library and all responsibilities of the request creation and response handling also lie with the core libraries, making SDKs clean and easy to maintain.
Cleaner API Call
Simplified and cleaner API call code is the finest benefit added to our Java SDKs through core libraries. Now, in addition to moving all of the serialization, deserialization, and request parameter validation code into the core libraries, we have also included the code for executing API calls and handling errors. Applying authorization parameters to the requests also introduces abstraction.
Before, a Java endpoint used to look like this:
/**
* @param dates Required parameter: Example:
* @return Returns the ServerResponse response from the API call
* @throws ApiException Represents error response from the server.
* @throws IOException Signals that an I/O exception of some sort has occurred.
*/
public ServerResponse dateArray(
final List<LocalDate> dates) throws ApiException, IOException {
HttpRequest request = buildDateArrayRequest(dates);
HttpResponse response = getClientInstance().execute(request, false);
HttpContext context = new HttpContext(request, response);
return handleDateArrayResponse(context);
}
/**
* Builds the HttpRequest object for dateArray.
*/
private HttpRequest buildDateArrayRequest(
final List<LocalDate> dates) {
//validating required parameters
if (null == dates) {
throw new NullPointerException("The parameter \"dates\" is a required parameter and cannot be null.");
}
//the base uri for api requests
String baseUri = config.getBaseUri();
//prepare query string for API call
final StringBuilder queryBuilder = new StringBuilder(baseUri
+ "/query/datearray");
//load all query parameters
Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("dates", DateTimeHelper.toSimpleDate(dates));
//load all headers for the outgoing API request
Headers headers = new Headers();
headers.add("accept", "application/json");
//prepare and invoke the API call request to fetch the response
HttpRequest request = getClientInstance().get(queryBuilder, headers, queryParameters,
null);
// Invoke the callback before request if its not null
if (getHttpCallback() != null) {
getHttpCallback().onBeforeRequest(request);
}
return request;
}
/**
* Processes the response for dateArray.
* @return An object of type ServerResponse
*/
private ServerResponse handleDateArrayResponse(
HttpContext context) throws ApiException, IOException {
HttpResponse response = context.getResponse();
//invoke the callback after response if its not null
if (getHttpCallback() != null) {
getHttpCallback().onAfterResponse(context);
}
//Error handling using HTTP status codes
int responseCode = response.getStatusCode();
//return null on 404
if (responseCode == 404) {
return null;
}
//handle errors defined at the API level
validateResponse(response, context);
//extract result from the http response
String responseBody = ((HttpStringResponse) response).getBody();
ServerResponse result = ApiHelper.deserialize(responseBody,
ServerResponse.class);
return result;
}
Now, because of core libraries, a Java SDK endpoint looks like this instead:
/**
* @param dates Required parameter: Example:
* @return Returns the ServerResponse response from the API call
* @throws ApiException Represents error response from the server.
* @throws IOException Signals that an I/O exception of some sort has occurred.
*/
public ServerResponse dateArray(
final List<LocalDate> dates) throws ApiException, IOException {
return prepareDateArrayRequest(dates).execute();
}
/**
* Builds the ApiCall object for dateArray.
*/
private ApiCall<ServerResponse, ApiException> prepareDateArrayRequest(
final List<LocalDate> dates) throws IOException {
return new ApiCall.Builder<ServerResponse, ApiException>()
.globalConfig(getGlobalConfiguration())
.requestBuilder(requestBuilder -> requestBuilder
.server(Server.ENUM_DEFAULT.value())
.path("/query/datearray")
.queryParam(param -> param.key("dates")
.value(DateTimeHelper.toSimpleDate(dates)))
.headerParam(param -> param.key("accept").value("application/json"))
.httpMethod(HttpMethod.GET))
.responseHandler(responseHandler -> responseHandler
.deserializer(
response -> ApiHelper.deserialize(response, ServerResponse.class))
.globalErrorCase(GLOBAL_ERROR_CASES))
.build();
}