-
Notifications
You must be signed in to change notification settings - Fork 2
Programmatic use
Part of the design goal for Sapi is to allow APIs to be constructed programmatically, giving us complete freedom to customize the API implementation.
While sapi2 allow us to define endpoints via external configuration files it is possible to combine programmatic and configured endpoints in a single application.
Step | Description | Data structure |
---|---|---|
Request | Request arrives as a GET or POST either at a custom or generic JAX RS endpoint. The requested URI and any path or query parameters are encapsulated in ... | Request |
Request embellishment | Programmatic code can add new parameters or mark others as "consumed" | Request |
Call set up | Determine the EndpointSpec instance that defines the query to run. Encapsulate the request, the endpoint specification and, optionally, a Velocity rendering template as ... | Call |
Obtain query builder | The EndpointSpec delivers the query builder customized by the Request. In the case of a Describe query this will be the raw query builder with the ?id variable bound to the requested URI. In the case of a List query all of the RequestProcessors registered in the API will be run (by default these inject sorting, offset/limits and filters). |
QueryBuilder |
Obtain query | Further bindings and manipulations can be made to the query by the caller, eventually calling .build() to create a query |
Query |
Execute query | The configured datasource is queried using the instantiated Query returning ... | ResultOrStream |
Render | The returned result or result stream is passed back as a JAX RS entity, marshallers take care of rendering to RDF, JSON, CSV and HTML. In the case of HTML the velocity template to use is found from the Request embedded in the results. | ResultOrStream |
Typically a JAX RS resource class will inherit from EndpointsBase
which provides convenience methods.
Default handler which will describe the URI request or run a list endpoint defined by an externally configured specification with an explicit uri
:
@Path("/{__path:.*}")
public class DefaultHandler extends EndpointsBase {
@GET
public Response handleDefault() {
return defaultResponse();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response handleDefault(String body) {
return defaultResponse(body);
}
}
The strange name for the path pattern variable (__path
) is to hide it from the parameter checks.
@GET
public Response getList() {
Call call = getCall("endpoint");
// custom preparation
return respondWith( call.getResults() );
}
The call
contains the request, the named endpoint (or the dynamically configured one that matches this URL if you don't given a name). This is enough to support custom processing of the query parameters and customization of the query by using call.getQueryBuilder()
, manipulating the query builder and then inserting back using call.setQueryBuilder()
.
For full control then the expanded version of the above method body is:
Request request = getRequest();
// embelish request
Call call = new Call(getAPI(), endpointName, request);
QueryBuilder builder = call.getQueryBuilder();
// additional query preparation here
builder = call.finalizeQueryBuilder( builder );
Query query = builder.build();
ResultOrStream result = null;
if (query instanceof ListQuery) {
result = getAPI().getSource().query((ListQuery)query, this);
} else {
result = getAPI().getSource().query((ItemQuery)query, this);
}
return respondWith(result);