Everything discussed in the Twitch live sessions for MuleSoft beginners.
- Follow me on Twitch to see the live streams: DevAlexMartinez
- Or watch the recorded and edited (shorter) versions on ProstDev's YouTube channel
All edited videos have been published and updated in the links below!
Session | Title | Description | Twitch | YouTube |
---|---|---|---|---|
0 | Planning the Outline | Based on the book MuleSoft for Salesforce Developers , we reviewed the relevant topics and created an appropriate outline for the upcoming sessions. More info here. |
Full video (55min) | Edited video (38min) |
1 | MuleSoft Overview | We went through an overview of the different MuleSoft products and how to get involved with the community. More info here. | Full video (1h2min) | Edited video (34min) |
2 | What is an API? | We explained the API basics and learned what is MuleSoft's API-led connectivity approach. More info here. | Full video (1h1m) | Edited video (35min) |
3 | Design an API Specification | We created the requirements for our Blog API and started designing our API Spec. Finish your homework before the next session! More info here. | Full video (1h16m) | Edited video (42min) |
4 | Test & Publish the API Spec | We tested the API Specification using the mocking service in Design Center and adjusted a few things we had to change. Then, we published the API Spec to Exchange. Finally, we created a new Mule project from the published asset. More info here. | Full video (1h10m) | Edited video (27min) |
5 | Develop the API in Anypoint Studio | We created a new Mule project with the scaffolded flows from the published API specification and started our API implementation / development. More info here. | Full video (1h19m) | Edited video (37m) |
6 | Debug the Mule App in Anypoint Studio | We reviewed how to implement the articles logic, created a Postman collection with its local+dev environments, and learned how to debug our Mule application. More info here. | Full video (1h) | Edited video (39m) |
7 | Deploy the Mule App to CloudHub (Runtime Manager) | We confirmed the API works locally, so we deployed it to CloudHub (located in Runtime Manager) to test it in the dev environment. More info here. | - Part 1 Full video (18m) - Part 2 Full video (1h2m) | Edited video (14m) |
8 | Set up CI/CD & API Autodiscovery (API Manager) | We connected our Mule app from Runtime Manager to our API in API Manager to apply security policies using API Autodiscovery. We learned how to apply CI/CD pipelines to our local project and how to do them using GitHub Actions. | Full video (1h15m) | Edited video (27m) |
9 | Test your Mule app with MUnit testing (manually from Anypoint Studio) | We created some MUnit tests for our Mule app's flows and ran them in Anypoint Studio to increase the MUnit coverage. | Full video (1h16m) | Edited video (58m) |
MuleSoft Overview
- MuleSoft products
- Anypoint Platform - You can create as many free trial accounts as you want! Just change the username in each account.
- Anypoint Studio - Main IDE
- DataWeave
- Anypoint Code Builder (BETA) - STILL IN BETA!!! DO NOT USE YET!
- Composer
- MuleSoft RPA
- Community overview
- Trainings/certification
Other resources
- Sravan Lingam's MuleSoft Training for Absolute Beginners
- Jitendra Bafna's Mule Technology Academy - Zero To Hero
- Whitney Akinola's blog
- Joshua Erney's jerney.io blog
- Alex's ProstDev blog and YouTube channel
- Edgar Moran's blog
- Mulesy
- Arul Alphonse's TechLightning courses and YouTube channel
What is an API?
- Understanding APIs
- Understanding APIs (Part 1): What is an API?
- Understanding APIs (Part 2): API Analogies and Examples
- Understanding APIs (Part 3): What are HTTP Methods?
- Understanding APIs (Part 4): What is a URI?
- Understanding APIs (Part 5): Intro to Postman and Query Parameters
- Understanding APIs (Part 6): What are HTTP Status Codes?
- MuleSoft's API-Led connectivity approach
- Experience layer: Top layer. These APIs connect with the client applications like a Mobile app, a Web app, or a Smartwatch app.
- Process layer: Middle layer. These APIs orchestrate the Experience and System layers.
- System layer: Bottom layer. These APIs connect with the server applications or third-party systems like SAP, Facebook, Salesforce, etc.
Other resources
Design an API Specification
- Step 1: Write down requirements
- Step 2: Design the API spec in Design Center
- Anypoint Platform > Design Center > Create > New API Specification
- Name:
Blog API
Guide me through it
- Create API
- This is the RAML we generated during the session.
Homework for next session
- Finish creating the API Specification with the resources we didn't get to create during the session:
Writers
,Categories
, andComments
. - The solution will be added to this repo before the next session.
Alex's homework solution
Remember we can all have different API designs depending on what we are trying to achieve with our API. This is the solution that I created for what I believe is the correct design. But please feel free to send me a message if you have a different solution!
Steps:
-
I modified the data types we created in the last session. Updated requirements can be found here.
a)
Article
data type:* writerId (number) -> writer (Writer) * categoryId (number) -> category (string)
b)
Writer
data type:* removed articles
c)
Category
data type was removed since it was transformed to just a stringd)
Comment
data type:* removed articleId
-
I created a new API Specification using
RAML 1.0
instead of the visual UI. This will make it easier moving forward for us to compare each other's results. -
Inside this new API Spec, I created a
types
folder with our data types:- Article
- Comment
- Error
- Writer
-
The final resources I created are as folows:
/articles /articles/{id} /articles/{id}/comments /articles/{id}/comments/{id} /writers /writers/{id} /categories
-
I decided to use a query parameter on the
/categories
resource to query if a specific category (string) exists or not. A similar approach would be done with the comments. If you don't want to have such a long URI like/articles/1/comments/1
, you can also decide to use query parameters instead. This is completely up to your design/preference. -
Finally, the whole code I generated can be found here. You can decide to use this design to continue with the rest of the sessions, or continue with your own API spec!
Publish an API Specification
- Step 1: Test your API Spec using the mocking service (adjust spec if needed)
- See sessions/4/in-session-spec.raml for what we adjusted during the session
- Step 2: Publish to Exchange
- Step 3: Create a new Mule project in Studio, importing the API Spec from Exchange to scaffold the flows
- See sessions/4/studio-project for the project we created during the session
Other resources
Develop the API in Anypoint Studio
- Step 1: Scaffold the flows in Studio from the API Specification we had published to Exchange (we did this at the end of session 4)
- Step 2: Move the Global Elements from
maxines-blog-api.xml
to a newglobal.xml
file - Step 3: Create the
local.properties
anddev.properties
to keep separate properties per environment (you can also use .yaml) - Step 4: Add a Global Property
env
with the valuelocal
- Step 5: Add a Configuration Properties for the file
${env}.properties
- Step 6: Create the
default.properties
file and its Configuration to keep the common values - Step 7: Start the API implementation using Object Store (you can also connect to a database or an external service if you want)
- This is the project we generated during the session
- To see all the changes to the Mule project in this session, refer to this commit: fa444df
Other resources
Homework for next session
- 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
articles
resource (happy path) - 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
Alex's homework solution
Remember we can all have different solutions. You don't have to do exactly what I do. This is just to guide you or give you a better idea of what other solutions you can implement.
You can see the full list of changes I did for this homework in this Pull Request
Since this solution is a bit bigger, I'll break this down in stages.
Stage 1: Updating the RAML
Steps:
-
I decided to add a
POST
and aDELETE
to the/categories
resource. To do this, I went back to Design Center and implemented those two methods in the RAML./categories: post: body: type: string[] example: ["Programming"] responses: 201: body: type: string[] example: ["MuleSoft", "DataWeave", "Programming"] 409: body: Error delete: body: type: string[] example: ["DataWeave"] responses: 204: 404: body: Error 409: body: Error
-
I also updated the version in the RAML (should be at the top).
version: 1.0.2
-
After that, I published these changes to the Exchange asset just by clicking the
Publish
button at the top-right. -
Once the changes are in Exchange, I went back to Anypoint Studio and selected
Maxine's Blog API
>Update version
. -
You can click on the
check for updates
button at the top-right of the new window to reflect the latest version. Make sure you are signed in to your Anypoint Platform account, otherwise you might have issues updating. -
A workaround to this, if you experience a lot of issues with updating via the UI, is to go to your
pom.xml
and manually update the version in the dependencies. For example, this is how it looks like in my project:<dependency> <groupId>25cebd62-2548-4351-8196-5a262e78e663</groupId> <artifactId>maxines-blog-api</artifactId> <version>1.0.2</version> <classifier>raml</classifier> <type>zip</type> </dependency>
-
The UI should ask you if you want to add the new flows. You can say yes to do the scaffolding for those flows. The rest of your flows should remain untouched.
-
By this point, Studio correctly generated the two new flows for me:
delete:\categories:application\json:maxines-blog-api-config
post:\categories:application\json:maxines-blog-api-config
Stage 2: Creating new Mule Configuration Files per resource
Steps:
-
I created the following files:
resources-articles.xml
resources-categories.xml
resources-comments.xml
resources-writers.xml
-
Inside these files, I created a sub-flow per HTTP Method. For example, the
resources-articles
file has the following sub-flows (note that these have some naming conventions that I decided to follow, like<config-file-name>:<flow-name>
, but you can name them however you prefer):resources-articles:read-all-articles
resources-articles:read-one-article
resources-articles:create-one-article
resources-articles:update-one-article
resources-articles:delete-one-article
-
Then, I added flow-refs to all the flows in
maxines-blog-api.xml
so the logic can live inside the new config files I created. -
Now I can directly modify the logic from the Mule Configuration Files instead of having to navigate through the huge main file.
NOTE: If you leave any of the flows or subflows empty, the application will not run. Make sure you add at least one logger (for example) to be able to run the app to test.
Stage 3: Creating the logic for the articles
resource
Steps:
-
Created four sub-flows to be reused by the rest of the flows.
-
Improved the logic to read all articles to reference the new
resources-articles:retrieve-all-articles-in-vars.articles
sub-flow. -
Created the logic to read one article by filtering the list of articles using DataWeave (Transform Message).
Code:
%dw 2.0 output application/json --- (vars.articles default [] filter ($.id ~= vars.articleId))[0]
-
Updated the logic to create one article.
-
Created the logic to update one article and used DataWeave to update the data.
Code:
%dw 2.0 output application/json --- vars.articles default [] map ( if ($.id ~= vars.articleId) payload else $ )
-
Created the logic to delete one article by filtering out the article by the
articleId
using DataWeave.Code:
%dw 2.0 output application/json --- vars.articles default [] filter ($.id != vars.articleId)
Note that for this last one we had to make sure the
articleId
variable was indeed a Number and not a String. The URI Parameters or the Query Parameters are usually of type String. You need to use further DataWeave code to transform it to a Number when applicable. In this case, we used the following code when we create the variable:attributes.uriParams.'articleId' as Number
Debug the Mule App in Anypoint Studio
- Mule Events
- Postman
- See the changes we did to the repo in this session: Pull Request #2
Homework for next session
Finish creating the rest of the requests in Postman from our API specification.
Alex's homework solution
- Created the rest of the requests in Postman.
- You can see the full list of changes I did for this homework in Pull Request #3.
Note
I worked on some improvements to the code's implementation before session 7. These changes were not included as session 6's homework and that's why I did not add them as part of that pull request. You can see all the improvements I did on commit 60a9813.
Deploy the Mule App to CloudHub
- Since my past Anypoint Platform account had already expired, I had to create a new API Specification in the new account and publish to Exchange
- For this to be updated in the Mule app, I had to modify the
pom.xml
and theglobal.xml
files to reflect the new asset - See the changes we did to the repo in this session: Pull Request #4
- For this to be updated in the Mule app, I had to modify the
- We learned how to deploy the Mule app to CloudHub manually from Anypoint Studio
- We learned the UI of Runtime Manager
Set up CI/CD & API Autodiscovery
- See the changes we did to the repo in this session: Pull Request #5
- Step 1: Retrieve your Anypoint Platform credentials:
- Access Management > Business Groups > select your business group > Environments > Sandbox (or your environment)
- Here you can retrieve your Client ID and Client Secret, which we'll refer to as:
ap.client.id
&ap.client.secret
from the Maven commandanypoint.platform.client_id
&anypoint.platform.client_secret
from the Mule app's properties
- Step 2: Retrieve your Connected App's credentials:
- Access Management > Connected Apps > Create app > App acts on it's own behalf
- Scopes:
- Design Center Developer
- View Environment
- View Organization
- Profile
- Cloudhub Organization Admin
- Create Applications
- Delete Applications
- Download Applications
- Read Applications
- Read Servers
- Retrieve Client ID and Client Secret, which we'll refer to as:
CONNECTED_APP_CLIENT_ID
&CONNECTED_APP_CLIENT_SECRET
from GitHub Actions secretsconnectedapp.client.id
&connectedapp.client.secret
from the Maven command
- Step 3: Modify your
pom.xml
:
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<!-- Deployment config start -->
<configuration>
<cloudHubDeployment>
<uri>https://anypoint.mulesoft.com</uri>
<muleVersion>4.4.0</muleVersion>
<applicationName>maxines-blog</applicationName>
<environment>Sandbox</environment>
<workerType>MICRO</workerType>
<region>us-east-2</region>
<workers>1</workers>
<objectStoreV2>true</objectStoreV2>
<connectedAppClientId>${connectedapp.client.id}</connectedAppClientId>
<connectedAppClientSecret>${connectedapp.client.secret}</connectedAppClientSecret>
<connectedAppGrantType>client_credentials</connectedAppGrantType>
<properties>
<env>dev</env>
<anypoint.platform.client_id>${ap.client.id}</anypoint.platform.client_id>
<anypoint.platform.client_secret>${ap.client.secret}</anypoint.platform.client_secret>
</properties>
</cloudHubDeployment>
</configuration>
<!-- Deployment config end -->
</plugin>
- Step 4: If you want to set it up with GitHub Actions, you can follow this quick reference
- Make sure you add the actual credentials to the GitHub secrets in Settings > Secrets and variables > Actions > New repository secret
CONNECTED_APP_CLIENT_ID
CONNECTED_APP_CLIENT_SECRET
ANYPOINT_PLATFORM_CLIENT_ID
ANYPOINT_PLATFORM_CLIENT_SECRET
- And make sure you modify the maven command to include all 4 credentials. Like so:
- Make sure you add the actual credentials to the GitHub secrets in Settings > Secrets and variables > Actions > New repository secret
mvn deploy -DskipMunitTests -DmuleDeploy \
-Dmule.artifact=$artifactName \
-Dconnectedapp.client.id="${{ secrets.CONNECTED_APP_CLIENT_ID }}" \
-Dconnectedapp.client.secret="${{ secrets.CONNECTED_APP_CLIENT_SECRET }}" \
-Dap.client.id="${{ secrets.ANYPOINT_PLATFORM_CLIENT_ID }}" \
-Dap.client.secret="${{ secrets.ANYPOINT_PLATFORM_CLIENT_SECRET }}"
- Step 5: If you want to test this locally (as we did on the session), you just have to run the Maven command in your Terminal with your actual credentials. Like so:
mvn deploy -DskipMunitTests -DmuleDeploy \
-Dconnectedapp.client.id="ae0bd2e7fd154c3adf1cc934543a07e" \
-Dconnectedapp.client.secret="2Da6676dad64640B265D9Cc35830478" \
-Dap.client.id="5e09b8bf52394797b5035978b74aee1" \
-Dap.client.secret="D4dD12915E3D29d9aB436AA0849c519"
Links & Resources
Resources
Test your Mule app with MUnit
- See the changes we did to the repo in this session: Pull Request #6