Routing API requests - department-of-veterans-affairs/abd-vro GitHub Wiki

This page describes how API requests are routed to a microservice and an API response is sent back to the client, leveraging Apache Camel to provide most of the glue code and common Enterprise Integration Pattern (EIP) implementations.

Synchronous API request

Referring to the code version after PR #71 was merged. To run the code, see Development process and open http://localhost:8110/swagger in a browser to see the API spec, including the "Demo API" provided by the DemoController mentioned below.

  • In the app Docker container, when a Controller class receives an API request, it converts the requests into a model, feeds that model as a message into a Camel route, and converts the result of the last route endpoint into an API response object for sending back to the client -- see DemoController for an example.
  • The DemoController uses CamelEntrance to inject messages into a Camel endpoint for Camel routing.
  • Camel routes are defined by RouteBuilder subclasses, like PrimaryRoutes and ClaimProcessorRoute. For example,
    • DemoController.assess_health_data calls CamelEntrance.assess_health_data_demo
    • to inject an AssessHealthData message into the direct:assess_health_data_demo endpoint,
    • which is defined in PrimaryRoutes as a route that goes to rabbitmq:assess_health_data?routingKey=health_data_assessor (the health_data_assessor queue in RabbitMQ's assess_health_data direct exchange -- RabbitMQ/AMQP concepts).
  • In a separate service-ruby Docker container, a Ruby microservice is subscribed to RabbitMQ's health_data_assessor queue (using RabbitSubscriber service-ruby/src/lib/rabbit_subscriber.rb). As configured in microservices.rb, when a message is popped out of that queue, HealthDataAssessor will process the message and return a result, which is sent as a reply RabbitMQ message.
    • It is intended that communication with microservices use RabbitMQ, typically via a direct exchange and routing key to the queue. The message should be a JSON string (automatically encoded as byte[]) -- this will facilitate replacing RabbitMQ with other messaging systems (like AWS SQS) if needed.
  • The reply message is received back on the Camel route in the app Docker container. When the last endpoint on the route is completed, the last message is converted to the return object of CamelEntrance.assess_health_data_demo, which will be mapped to the API response object in DemoController.

"Asynchronous" API request

When an API request takes more than 30 seconds to complete, consider sending an immediate API response that includes a URL for the client to check on the status and/or to poll for the result. For an example, check out the POST claim API in the CamelApp, where a claim is processed asynchronously in the background and the claim's status is updated to reflect processing completion.

To achieve this, we leverage the recipientList EIP to send the POSTed claim to multiple endpoints. Since all the endpoints are configured to be asynchronous, we do not wait for any of the results and move on to the next endpoint of the Camel route (using the same message that was sent to the recipientList).

Dynamic Routing

When the route of a claim (a.k.a., a Camel message) is determined dynamically (e.g., based on the claim characteristics or the processing logic), we use a dynamicRouter EIP. For example the DynamicClaimRouter class routes a claim to an endpoint depending on claim's contentionType attribute. A more complete example is provided in the CamelApp.