Part 2: Building a Data Query Application
In a previous blog, we talked through how you might design a solution to deliver a Command Query Responsibility Segregation (CQRS) pattern with Anypoint Platform. In this blog, we’ll discuss how an API-led connectivity approach can help you deliver this pattern (and the mobile application your business is demanding) with speed and scale while maintaining control over your critical data assets.
API-led connectivity and API design
To deliver this mobile application successfully, you need to bring together two groups of people:
- Your client’s Supplier Relationship Management (SRM) domain experts
- Your developers implementing the mobile application and underlying connectivity
You discovered RAML, the RESTful API Modeling Language, to start design discussions between your client’s SRM experts and your mobile and backend developers. RAML is a language of the web and therefore can be understood and interpreted by technical and non-technical people alike. This means it’s practical for supporting cross-team communication. By iterating on the RAML specification, the team can jointly discover how to deliver great business value and accurate resource naming like “item” or “part”, “material” or “product”, etc. Imagine the following design was agreed as sufficient for the first prototype implementation.
The power of RAML for driving Consensus
Let’s now discuss how you might have gotten the non-technical domain experts on board.
The picture above shows the RAML design for the API you want to build.
After some conversations with your clients, you identified the “construction-machine” API needed to be provide search for parts (/parts/search). You also discovered that parts should be accessible via a resource id (/parts/{part_id}), and that every part has a price (/parts/{part_id}/price). Additionally, in the first iteration suppliers should also be searchable (/suppliers/search).
With this contract in place (agreed upon by both parties), you can now begin thinking about implementation. And while you work on implementing the API, front-end developers can begin coding against a mocked version leveraging sample data you provide with the mocking service available in API Designer.
Data Query Application Implementation
The first step in building the Data Query Mule application is to load the mutually agreed RAML specification into Anypoint Studio, which then creates a stub implementation of your API. This application by itself is now runnable and can be deployed on any Mule runtime, either in the cloud or on-premises.
The second step in building the application is to add a Mule XML configuration file to host your Neo4j graph database functionality. It includes Cypher query generation and reaches out to your Neo4j installation to run the query via the Neo4j REST API.
This kind of separation gives you freedom to grow your application’s functionality in future versions of your project should you decide to move away from Neo4j.
The complete functioning solution can be reviewed here.
Solution In Action
Now let’s see this implementation in action with an example. Suppose a user is querying your API from a mobile device in order to retrieve all parts that belong to your client’s Excavator Chassis (e.g. with part id = 13). The user is requesting the following resource: http://localhost:8081/api/parts/search?belongs-to=13.
- APIKit router validates all incoming requests from the mobile device and outgoing message formats according to your RAML specification
- Depending on the request resource (e.g. /parts/search?belongs-to=13) the corresponding Mule flow is invoked
<flow name=”get:/parts/search:construction-config”> - The /parts/search flow extracts and validates the supplied query parameters
<add-message-property key=”belongsto”
value=”#[message.?inboundProperties[‘http.query.params’][‘belongs-to’] or -1]” /> - Query parameters were stored into a flow variable and used in the Choice router for correct handling
<when expression=”#[?belongsto >= -1]”>
<flow-ref name=”neo4j-adapter-search-parts-belongs-to”
doc:name=”neo4j-adapter-search-parts-belongs-to” />
</when> - The given belongs-to query parameter invokes a specific flow on the Neo4j adapter implementation that generates a corresponding Cypher query
<flow-ref name=”neo4j-adapter-search-parts-belongs-to”
doc:name=”neo4j-adapter-search-parts-belongs-to” /> - The Neo4j API for single transaction Cypher queries (db/data/transaction/commit) is invoked using the standard Mule HTTP connector
<flow name=”neo4j-adapter-search-parts-belongs-to”>
<set-payload value=”{ “statements” : [ { “statement” : “match
(n:Part)-[:belongsTo]->(p:Part) where p.itemId=#[belongsto] return n” }
]}” doc:name=”Set Payload”/>
<flow-ref name=”neo4j-adapter-call-out” doc:name=”neo4j-adapter-call-out”/>
</flow> - Neo4j answers with a JSON response containing the query result
- DataMapper is used to transform the Neo4j JSON result message to your XML Schema format
<data-mapper:transform config-ref=”JSON_To_Xml_search_result_” doc:name=”JSON To Xml search-result” /> - The API XML response is returned to the Caller, in this case a mobile device
Extending the application with business logic.
With the data query solution working smoothly, you can now move on to address the requirement of real-time currency conversion. The goal: every item’s price can be retrieved with the current exchange rate. For that, you wrote a Currency Converter using Google Finance and Anypoint DevKit.
Once built, you can drop the custom connector into the API resource /parts/{part_id}/price flow. First, look it up in your Connectors list:
Then add it to your API implementation flow…
… and finally configure the currency conversion to be dynamic.
Now you have a functioning resource for all parts prices. Whatever Euro amount Neo4j returns is dynamically converted into the requested currency code. Another requirement solved!
The Impact of API-led Connectivity
If we take a step back and think through the solution we just created, a few key advantages come to mind:
- API-led Connectivity ensures alignment across business and IT at critical design-time
- Exposable and manageable experience API hides backend complexity
- Solution was delivered without custom code, increasing speed of delivery
- Solution can be deployed on-premises or in the cloud, with one Mule runtime
- Each application component acts as subdomain in Mule, nicely separated and extendable without affecting the other parts of the solution
- The business can switch from Neo4j to another storage solution without affecting the API, it would only require you to reference the new storage adapter
- You can refactor the Data Query Application into two single applications by using an asynchronous protocol (JMS, AMQP) to decouple them instead of a flow reference
- That could prove very useful if the API implementation needs to scale up massively
- Cypher is powerful but developers or API user might not want to learn it
- The real-time currency converter is now a reusable component built quickly with functionality available to every developer in Anypoint Studio
Ready to start your own innovation project? Get started with Anypoint Platform. The next post will discuss how to build a write API.