One of the components generated by the Rhino REST API Framework is a resource adaptor type. This component contains all the service visible classes and interfaces you need to write Rhino TAS - Telecom Application Server based services.
-
A resource adaptor Provider interface for your RA type
-
An
ACI
Factory object -
A Client interface for your REST API
-
An API interface for each
tag
used in your API specification -
Request and Response Events
-
Model classes and Enums
The following diagram explains the relation between the RA Provider, REST API Client and API interfaces.
Each RA Type defines one provider interface. The resource adaptor is responsible for implementing this interface. The provider defines a factory operation for fetching a Client interface. The Client defines a factory operation per API that the REST API defines.
Learn about the Rhino REST API Framework Architecture |
Learn more about Resource Adaptors from JAIN SLEE (JSR 240). |
The following sections explain how to use the classes and interfaces in the REST API resource adaptor type.
Getting a provider and ACI factory
Rhino implements the SBB component environment, and provides it to the instances of the SBB component classes through the JNDI
interfaces.
You access a resource adaptor provider object using a JNDI
lookup.
For example the PingPongApiServerSbbPart constructor:
Unresolved directive in <stdin> - include::/mnt/ephemeral0/workspace/product/ra/rest-api-framework/release-1.0.0/Auto/rest-api-framework-docs/rest-api-framework-public-docs/rhino-rest-api-framework-users-guide/include/PingPongApiServerSbbPart.java[tag=sbbpart-constructor]
Review the generated sbb-part superclass as it contains the required annotations and code for obtaining a provider object. |
Getting an API object
The RA provider allows you to create a Client object. For example, the PetstoreApiServerProvider
interface is:
public interface PetstoreApiServerProvider {
/**
* Return an API Client instance.
* @param configuration the configuration to use for the instance of the API.
* @return an PetstoreApiServerApiClient instance.
*/
PetstoreApiServerApiClient getApiClient(ApiConfiguration configuration);
}
You get a Client interface by calling getApiClient()
, passing an ApiConfiguration
object as a parameter.
The ApiConfiguration
object defines the configuration to be used with a generated REST API such as the preferred body type
to be used when you create outgoing requests and responses.
You may call getApiClient() more than once, with different ApiConfiguration objects.
|
The PetstoreApiServerApiClient
interface is:
public interface PetstoreApiServerApiClient {
/**
* Return an api object related to the PetsApi API.
* @return an PetsApi instance.
*/
PetsApi getPetsApi();
}
The client interface has one accessor method per tag/API in your OpenAPI Specification.
Refer to the following examples: |
Deriving API interfaces from an openapi spec
Each API operation may have an associated list of tags.
For example, the List Pets request in the Pet Store API has a tag of Pets
.
The OpenAPI SLEE Generator uses tags to:
-
group operations into API interfaces
-
generate an accessor operation per API interface, in the Client interface.
Use tags in your openapi specifications to group related operations together in the generated API.
Model types
The OpenAPI SLEE Generator generates Java classes and Enums from the schemas
subsection of the components
section of your openapi specification.
See: Components. |
For example the Pet Store schema defines Pet and Pets, from which OpenAPI SLEE Generator will generate a Pet
class.
The generated model types implement Serializable, so can be stored in CMP fields.
In the future these will also be FastSerializable, for more efficient storage in CMP. |
Creating and Sending requests
Create and send requests by using an API object.
For example, the client API used in the REST API Framework Demonstration includes an NotificationApi
interface:
public interface NotificationApi {
// ...
// Create a RestRequestBuilder for request: CallDirectionNotification
RestRequestBuilder createCallDirectionNotificationRequest(
CallEventNotification callEventNotification);
// Create a RestRequestBuilder for request: CallEventNotification
RestRequestBuilder createCallEventNotificationRequest(
CallEventNotification callEventNotification);
// Send a request
OutgoingRestActivity sendRequest(
RestRequestBuilder requestBuilder) throws IOException;
}
See Introduction to Metaswitch Call Notification for more information. |
The content-type used is defined in your openapi specification. For example the callDirectionNotification
operation is:
/calldirection/notification:
post:
summary: A new Call Direction notification
operationId: callDirectionNotification
tags:
- notification
requestBody:
required: true
description: call direction notification
content:
application/json:
schema:
$ref: "#/components/schemas/CallEventNotification"
If an operation supports JSON or XML encoding, the configured preferredBodyType
(from the ApiConfiguration
)
dictates which encoding to use.
If no preferredBodyType
is specified, then the first JSON-compatible media type, from the list of supported types, is used.
Once the new outgoing request is created, it is sent using the API object’s sendRequest
method.
This method returns an OutgoingRestActivity
to which the application should attach
, so it will receive the associated response.
See Sending CallDirection and CallEvent notification requests for an example where a new CallEventNotification request is sent,
and the application attaches to the OutgoingRestActivity .
|
Creating and Sending responses
There are two methods for creating and sending responses:
-
Create the response by using an API object
-
Create the response from a Request event
Create the response by using an API object
Create and send responses by using an API object.
For example, the Pet Store API PetsApi
interface includes the following operations to create responses related to a ShowPetById
request:
/**
* Create a {@link RestResponseBuilder} for a _200_Success response, related to a ShowPetById request.
* @param contentTypeStr the desired Content-Type, as a string. If null, the default Content-Type
* will be selected from application/json
* based on the value of {@link com.opencloud.slee.rest.common.ApiOptions#preferredBodyType}
* in the {@link com.opencloud.slee.rest.common.ApiConfiguration}
* @param responseBody a Pet, may be null
*/
RestResponseBuilder createShowPetById_200_SuccessResponse(String contentTypeStr,
Pet responseBody);
/**
* Create a {@link RestResponseBuilder} for a Default response, related to a ShowPetById request.
* @param contentTypeStr the desired Content-Type, as a string. If null, the default Content-Type
* will be selected from application/json
* based on the value of {@link com.opencloud.slee.rest.common.ApiOptions#preferredBodyType}
* in the {@link com.opencloud.slee.rest.common.ApiConfiguration}
* @param responseBody a Error, may be null
*/
RestResponseBuilder createShowPetByIdDefaultResponse(int statusCode,
String contentTypeStr,
Error responseBody);
Once the new outgoing response is created, it is sent using the API object’s sendResponse
method.
/**
* Send a response.
* @param responseBuilder the response to be sent.
* @throws IOException if the response could not be built or sent.
*/
void sendResponse(RestResponseBuilder responseBuilder, ActivityContextInterface aci)
throws IOException;
Create the response from a Request event
The generated request event objects include methods for creating the associated responses.
For example, the ShowPetByIdRequest
event class includes these methods.
/**
* Create a {@link RestResponseBuilder} for a 200 Success response.
* @param contentTypeStr the desired Content-Type, as a string. If null, the default Content-Type
* will be selected from application/json
* based on the value of {@link com.opencloud.slee.rest.common.ApiOptions#preferredBodyType}
* in the {@link com.opencloud.slee.rest.common.ApiConfiguration}
* @param responseBody a Pet, may be null
*/
public RestResponseBuilder create_200_SuccessResponse(String contentTypeStr,
Pet responseBody)
{
// method implementation not shown
}
/**
* Create a {@link RestResponseBuilder} for a Default response.
* @param contentTypeStr the desired Content-Type, as a string. If null, the default Content-Type
* will be selected from application/json
* based on the value of {@link com.opencloud.slee.rest.common.ApiOptions#preferredBodyType}
* in the {@link com.opencloud.slee.rest.common.ApiConfiguration}
* @param responseBody a Error, may be null
*/
public RestResponseBuilder createDefaultResponse(int statusCode,
String contentTypeStr,
Error responseBody)
{
// method implementation not shown
}
In the following example, process a ShowPetById
by querying the Pets DB.
If there exists a Pet corresponding to PetId
then create a 200 success response (create_200_SuccessResponse("application/json", toShow)
).
Otherwise create a 501
error response.
private void handleShowPetByIdRequest(ShowPetByIdRequest request,
ActivityContextInterface aci) throws IOException
{
final Pet toShow = getPet(request.getPetId());
if (null == toShow) {
tracer.finest("Show pet with id: {} = {}", request.getPetId(), toShow);
final RestResponseBuilder errorResponse = request.createDefaultResponse(
501,"application/json",
new Error().code(501).message("There is no pet with id: " + request.getPetId()));
sendResponse(errorResponse, aci);
}
else {
sendResponse(request.create_200_SuccessResponse("application/json", toShow), aci);
}
}
Once the new outgoing response is created, it is sent using the API object’s sendResponse
method.
private void sendResponse(RestResponseBuilder response, ActivityContextInterface aci) {
try { petsApi.sendResponse(response, aci); }
catch (IOException e) {
tracer.finest("Failed to send response. Api = {} , OperationId = {}",
response.getApi(), response.getOperationId(), e);
}
}