Implementing request/response protocols with the HTTP connectivity transport
Apama's REST server, provided by the HTTP server connectivity transport, could only provide event submission over REST. With the 10.3.1 release (available to both Software AG 10.3 and 10.4 customers), it can now also provide request/response APIs. This article explores some of the new functionality.
REST use cases with Apama
Apama is an event-processing engine, which needs to integrate with other systems to consume and emit events. This has traditionally been through either our own client libraries and protocol or via messaging busses, such as Java® Message Service (JMS) or Universal Messaging. In the past few releases, we have been adding ways to directly integrate with Apama through standard web-based protocols, such as REST.
Querying/invoking a REST service from Apama
Some Apama applications need data from external services in order to process events. The results of other applications are actions on an external service. In Apama 10.0, we introduced an HTTP Client transport, which could be used to make such requests from your Apama application, wait for the response and handle it.
Event delivery to Apama over REST
Alternatively, you might have an external service that needs to deliver an event stream to Apama. In 10.1, we introduced an HTTP Server transport which provides an HTTP REST endpoint, which you can invoke from other services. This version of the HTTP Server was one way. You could deliver an event to Apama, but Apama couldn't give you any response from the application.
Apama provides a REST service
Rather than just providing a submission-only API, you might want to provide a full REST service where the query is handled by your Apama application which decides on how to respond. This response is then what's sent back to the client. This use case is what we're providing in 10.3.1 and will be the subject of the rest of this article.
Adding HTTP Server support to a project
To add an HTTP server to your project, you need to add the “HTTP Server” bundle. This can either be done in Software AG Designer through the “Connectivity and Adapters” node or using the new apama_project tool also introduced in 10.3.1.
This will add an additional YAML configuration file and associated properties to your project under config/connectivity/HTTPServer. You will need to modify the properties file to specify the port you want to run the server on and change any other settings like TLS support. More details about the configuration options can be found in Apama documentation.The default configuration is a submission-only JSON™-based API, which assumes a particular format of the JSON payload. You will have to change this configuration file to enable request/response and provide a mapping between the bodies of the REST API to events within Apama (see below).
Enabling REST responses from EPL
By default, the HTTP server bundle will have a submission-only API and not allow you to send responses from your EPL. In order to be a full REST server, you'll need to change the configuration file. We're going to create a Create Request Update Delete (CRUD) store in which you can make a request to store data in Apama and then retrieve it later. The full example can be found in the samples/connectivity_plugin/application/httpserver-responses directory of your Apama installation.
First, you have to stop the transport from sending responses automatically by changing a flag on the transport:
HTTPServerTransport:
automaticResponses: false
allowedMethods: [PUT]
Second, the transport provides some information which needs to be mapped into an event so that you can use it in EPL. This is done by changing the rules for the mapperCodec in your chain definition in the configuration file:
mapperCodec:
“*”:
towardsHost:
mapFrom:
- payload.requestId: metadata.requestId
defaultValue:
- payload.channel: “@{httpServer.responseChannel}”
This snippet is applying to all request messages, and we're setting two fields in the payload. The request ID is taken from each message and the response channel is a constant substituted in when the chain is created. You will need to add these mapping rules in addition to any others you have for all types of request. The request ID is used to match up responses to the appropriate request. The channel tells EPL how to send responses back to the transport.
We also need to make some changes to messages coming back from EPL. Specifically, we need to provide that response ID from the corresponding request:We also need to make some changes to messages coming back from EPL. Specifically, we need to provide that response ID from the corresponding request:
mapperCodec:
“*”:
towardsTransport:
mapFrom:
- metadata.requestId: payload.requestId
Handling REST requests and sending responses
Finally, we're ready to write some EPL, which will handle a request and send an appropriate response. Let’s use the “create” part of the CRUD sample as an example. You can see all the other versions in the full sample.
on all CreateObject() as co {
try {
string path := generateNewKey();
datastore.add(path, co.data);
send Success(co.requestId, path) to co.channel;
} catch (Exception e) {
send Error(co.requestId, 500, e.getMessage() to co.channel;
}
}
This shows that we're taking the request id from the CreateObject request and passing it back in both the Success and Error responses. These responses are being sent to the channel that's also part of the request object.
There will also need to be mapping rules for the success and error messages being sent back to the client. You can see the details in the full sample.
Summary
In this article we've learned how to handle REST requests in your Apama application and generate tailored responses to be sent to the client. Full details are available in the httpserver-responses sample in your installation and in the Apama documentation under “The HTTP Server Transport Connectivity Plug-in.” For more help, check out our regular blog posts at Apama community or ask a question on Stack Overflow with the apama tag.