MuleSoft from Start: A Beginner’s Guide — Session 5: Develop the API in Anypoint Studio
In the last session, we finished creating our API Specification, tested it, and published it to Exchange. After that, we used that asset from Exchange to create a Mule project with the scaffolded flows from the API Spec.
In this week’s session, we modified our newly created Mule project to follow best practices like having a specific file for Global Elements or creating properties files per environment. We also started the development of our API Implementation using the Object Store to keep our API data instead of connecting to an external database or a third-party service (for simplicity purposes).
Note: The links and notes from the session have been added to the GitHub repository for you to follow through with what I’m doing in the video. You can find both recordings (the complete and the shorter one) at the end of the post.
Global Elements file
Right-click on src/main/mule and create a new Configuration File. Name it global.xml. We will use this file to keep the Global Elements from the whole project inside just one Configuration File, instead of having them spread across different files.
Now go back to the main Configuration File that was created before (with the APIKit router), go to the XML view, and cut the two configurations for the HTTP Listener and for the Router. You will paste these into the new global.xml file, inside the <mule></mule> brackets.
That’s it! Moving on, you will be able to use this global.xml file to keep all the Global Elements. This will save you time in the future so you don’t have to look into all the Configuration Files to find your Global Elements.
Properties
There are certain values that you don’t want to keep hardcoded into the XML code in case you want to change them later. For example, the HTTP host or port. Besides that, you want to be able to have different values depending on the environment the application is running in. For this purpose, it is recommended to have different properties files located under src/main/resources.
Note: The properties files can be of type .properties or .yaml, but in this example we’re going to use .properties.
Right-click on src/main/resources and create two new files: dev.properties and local.properties.
Inside the local properties file, add the following properties:
http.host=0.0.0.0
http.port=8082
Inside the dev properties file, add the following properties:
http.host=0.0.0.0
http.port=8081
Now you can go to the Global Elements and edit the HTTP Listener configuration to refer to the properties we just created using the syntax ${property}. Like this:
In order for the Mule app to know which configuration file should it take depending on the name of the environment, we’re gonna have to add a few more configurations to connect all of these files.
In Global Elements, create a new Global Property with the name env and the value local. This way, every time we run this Mule app, it’s gonna know the environment is local. When we deploy this application to the cloud, we are going to create another property there to tell it the environment is now dev.
The final step is to actually add the files to read depending on this env property. To do this, create a new Global Element that is a Configuration Properties. In the File field, write ${env}.properties
This configuration will now read the value from the env property we set up (either local or dev), and replace it in the ${env} part to end up with either local.properties or dev.properties.
Developing the API
We decided to use the Object Store to keep our data instead of spending time creating a database, just for the sake of simplicity. During the video, we finished implementing the logic for GET /articles and POST /articles. In other words, to read all the articles and to post a new article.
This is the configuration we ended up creating for the GET:
<flow name="get:\articles:maxines-blog-api-config">
<logger level="INFO" message="Starting GET /articles" doc:name="START" />
<os:retrieve doc:name="GET articles" doc:id="d86a63ee-6e86-4301-b189-2c79f606f52c" key="#[Mule::p('os.articles')]" objectStore="Object_store" >
<os:default-value ><![CDATA[#[output application/json --- []]]]></os:default-value>
</os:retrieve>
<logger level="INFO" doc:name="END" doc:id="be2cfaf5-dd3f-473f-97dc-2f46323b9230" message="Ending GET /articles" />
</flow>
And for the POST:
<flow name="post:\articles:application\json:maxines-blog-api-config">
<logger level="INFO" message="Starting POST /articles" doc:name="START"/>
<os:retrieve doc:name="articles" doc:id="86c79bf7-248f-452d-afde-1f5605d69937" key="#[Mule::p('os.articles')]" objectStore="Object_store" target="articles">
<os:default-value ><![CDATA[#[output application/json --- []]]]></os:default-value>
</os:retrieve>
<ee:transform doc:name="append new article" doc:id="db752066-af0c-4635-9f1f-9340d20aef67" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
(vars.articles default []) + payload]]></ee:set-payload>
</ee:message>
</ee:transform>
<os:store doc:name="new article to 'articles'" doc:id="92d29f4d-58d7-4130-924b-32df7ae1be16" key="#[Mule::p('os.articles')]" objectStore="Object_store"/>
<remove-variable doc:name="articles" doc:id="72fe56a1-3265-4982-a670-98eaaebd0459" variableName="articles"/>
<logger level="INFO" doc:name="END" doc:id="0fefc982-dc69-4f25-bf9b-0b7ebbec86e2" message="Ending GET /articles"/>
</flow>
Homework
For you to practice — and because I can’t do it all in the 1-hour live stream :’D — we’ll work on the following things offline:
- Create new Mule Configuration Files to keep each resources’ logic separate from the main
maxines-blog-api.xml
file - Add subflows inside these new config files instead of flows
- Reference these new subflows from the main flows from the APIKit router
- Finish creating the logic for the rest of the resources (we just did
articles
in this session) - Improve the code to avoid duplicating the same code (like we do with the Retrieve connector named
GET articles
) -- this helps to avoid human mistake
I will post my homework solution before July 12 and we’ll meet again on July 19 to continue with the sessions :)
Recordings
Finally, here are the two recordings you can find about this session.
Here you can find the shorter version from YouTube:
And here you can find the complete video from Twitch:
Please let me know if you have any comments, suggestions, or just general feedback for me!