. . .

Development Advanced Topics

Starting with DeltaSync handling, this section will grow to contain all advanced topics regarding generated services.


DeltaSync (>= ApiOmat 20.03.1)

DeltaSync allows you to reduce the payload of responses that would contain multiple entities.
It can be applied to GET requests that return collections of a specific model (e.g. getAllModels or getReferences) and is controlled via the request headers. You can find more information about the underlying concept on the DeltaSync page.

DeltaSync is available since ApiOmat 20.03.1 (with Brewer 1.1.0).

This section explains how you can use DeltaSync in your generated service.

Implementation

You can use the following classes to implement the DeltaSync handling:

DeltaSyncRequestWrapper

The DeltaSyncRequestWrapper is an adapter class that wraps the HttpServletRequest and provides a convenient way to access DeltaSync headers of the request over its getter getDeltaSyncMap.
You'll get a Map with all DeltaSync headers that are contained in the request. The key is the header name and the value should be a String in JSON format.

RequestState

The RequestState is an automatically created, request scoped bean from our brewer-base library. It allows you to control the behavior for requests to the YAMBAS backend.
You can configure deltaSyncHandledByService, which indicates whether the service or YAMBAS handles the DeltaSync headers. The default value is false, which means that YAMBAS is handling DeltaSync.

ReponseState

The ResponseState is an automatically created, request scoped bean from our brewer-base library. It allows you to control the response of your service.

It holds a Map of DeltaSync headers which are merged with the headers added in the controller. To add headers to the Map, you can use the following methods:

  • addDeletionDeltaSyncHeader (set the x-apiomat-delta-deleted header with the IDs of deleted objects)

  • addRemovedDeltaSyncHeader (set the x-apiomat-delta-removed header with the IDs of removed objects)

These methods each take the DeltaSync header values as a parameter (e.g. the IDs of all models deleted since the last synchronization), convert them to an appropriate JSON String and set the pair of header key and header value to the DeltaSync Map.
Alternatively, you can construct the map of headers yourself and set it in the ResponseState bean with setHeaders.

For more details, please refer to the javadoc.

Usage (code examples)

In the <ModelClass>ApiServiceImpl component of your service, you can simply inject the following beans and make use of them as shown in the loadAll method.

<ModelClass>ApiServiceImpl.java 
@Autowired
private HttpServletRequest request;
 
@Autowired
private ResponseState responseState;
 
@Autowired
private RequestState requestState;
 
//...
 
@Override
public List<ModelClass> loadAll( final String appName, final String q, final boolean withClassnameFilter,
final boolean withReferencedHrefs )
{
/* Set handling of DeltaSync as a task of the service */
this.requestState.setDeltaSyncHandledByService( true );
final List<ModelClass> result = super.loadAll( appName, q, withClassnameFilter, withReferencedHrefs );
/* Wrap request so DeltaSync headers can be extracted */
final DeltaSyncRequestWrapper req = new DeltaSyncRequestWrapper( this.request );
 
/* Extract DeltaSync headers from request */
final String deltaSyncValue = req.getDeltaSyncHeaderValue( );
 
/* Implement DeltaSync handling */
if ( deltaSyncValue != null )
{
final Long lastSync = Long.parseLong( deltaSyncValue );
result.removeIf( e -> ( e.getLastModifiedAt( ).toEpochMilli( ) < lastSync ) );
}
/* Calculate deleted IDs and set as header value to response */
List<String> deletedIds = new ArrayList<String>();
/* Do calculation logic here ... */
 
this.responseState.addDeletionDeltaSyncHeader(deletedIds);
return result;
 }

Once you have implemented DeltaSync handling, you can test the behaviour by sending requests to your service that include DeltaSync headers. Timestamps (used in the DeltaSync header value) need to be Unix epoch time in milliseconds (thus a Long variable).

Example:

curl -i -X GET "${hostAddress}/yambas/rest/apps/${yourAppName}/models/${yourServiceName}/v/${yourServiceVersion}/${modelName}?hrefs=false&withClassnameFilter=true&withReferencedHrefs=false"
--header "X-apiomat-delta: ${timestamp}"
--header "Accept: application/json"
--header "X-apiomat-system: ${system}"
--header "X-apiomat-sdkVersion: ${sdkVersion}"
--header "X-apiomat-apikey: ${yourApiKey}"
--header "Authorization: ${auth}"
--header "X-apiomat-appname: ${yourAppName}"

Custom Headers in Requests to Yambas (>= ApiOmat 20.11.0)

You can use the request-scoped RequestState object to set additional headers for the requests to Yambas over a FeignClient. The RequestState provides methods to append custom headers. Please note that existing headers will be overwritten by your custom headers. If you need to append an header value, you have to append it manually. Alternatively, you can extend the class RequestHeaderRequestInterceptor and overwrite the addCustomHeaders method with your own implementation to change this behavior. Don't forget to configure this custom implementation in your application.yml.



CORS handling (>= ApiOmat 20.11.0)

This section explains how to configure Cross Origin Resource Sharing in your service - in other words, whether external pages can make cross domain requests to YAMBAS via your service.
CORS handling is available since ApiOmat 20.11.0 (with Brewer 2.0.0).

You can configure CORS handling via the following properties of your service (in src/main/resources/application.yml ):

  • {ServiceName}.cors-configuration.allowedOrigins: Set the allowed origins (URIs).

  • {ServiceName}.cors-configuration.allowedMethods: Set the allowed HTTP methods.

The default value for both properties is *, which means all origins and methods will be allowed as long as they are valid URIs/HTTP methods, respectively.
If either property is set to "none", or has an empty value, no CORS requests will be allowed at all!

Here is an example where CORS is enabled only for GET and HEAD requests from two specific URIs:

application.yaml
hobbitservice:
  cors-configuration:
    allowedOrigins:
      - "http://127.0.0.1:9081"
      - "https://other.secure.domain"
    allowedMethods:
      - GET
      - HEAD

When you start your service, the configuration class {ServiceName}CorsConfiguration will register all of your service's data model endpoints for CORS.
As part of this process, it retrieves the values for both properties and uses them as params for the registerMapping method of the Spring class CorsRegistry.

If you have created your own custom endpoints and need to enable CORS for them, simply add them to the list of endpoints in the addCorsMappings method of {ServiceName}CorsConfiguration.
For example:

<ServiceName>CorsConfiguration.java 
@Override
public void addCorsMappings( final CorsRegistry registry )
{
final String[ ] endpoints =
{
/* Regular data model endpoints */
"/apps/{appName}/models/HobbitService/**",
"/apps/{appName}/data/files/HobbitService/**",
"/apps/{appName}/data/images/HobbitService/**",
 
 
/* Custom endpoints */
"/apps/{appName}/custom/HobbitService/**",
"/apps/{appName}/admin/HobbitService/secret"
};
 
 
/* Register endpoints ... */
 }