Wednesday, July 7, 2021

Mule 4 Event Model

Mule Event and Mule Message:
When a request reaches the Event source of a flow (such as an HTTP request
 or a change to a database or file).  A mule event will be generated it creates mule event object. Mule event object primarily consists of information required to process by the Mule runtime. Mule event object travels through all the components configured in mule flow.

Mule event object is immutable, so every change to an instance of a Mule event object results in the creation of a new instance.
A Mule Event object is composed of these objects:
  1. A Mule Message contains a message payload and its associated attributes.
  2.  Variables are Mule event metadata that you use in your flow.

The sequence of the activities happens when event source receives the trigger
  • A trigger reaches the event source.    
  • The event source produces a Mule event.
  •  The Mule event travels sequentially through the components of a flow.Each component interacts in a pre-defined manner with the Mule event




How the Mule Event object get created from the incoming request ?
Standard message structure consists of Header and Payload parts, where Payload is core business information that need to processed and Header contains details about payload like encryption schemes, security credentials etc. Header content also called metadata. 

When a standard message reaches the Mule Event source (in other words its called Inbound Endpoint), Event source converts that message to Mule Event Object as Mule Event processors can only understand only Mule Event object. and handovers to next event processor.

Mule Event source creates Mule Event object by coping Header contents to Attributes section and Payload contents to Payload section



<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:file="http://www.mulesoft.org/schema/mule/file"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
<file:config name="File_Config" doc:name="File Config" doc:id="ce7b6ee8-e9f2-4370-b17f-2adf413d9826" >
</file:config>
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="825c4787-27c3-4595-baa3-5fa66d3ca97f" >
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<flow name="mule_event_demoFlow" doc:id="1bbf3a21-775f-49eb-9d06-48bb9f9a51dd" >
<http:listener doc:name="Listener" doc:id="a287d233-9054-423c-818d-e73a1fa67b51" config-ref="HTTP_Listener_config" path="/"/>
<logger level="INFO" doc:name="Logger" doc:id="cb41a866-d0a9-4a06-b7f4-5f75b3c62272" message="The City from source is #[message.attributes.headers.City]"/>
<set-payload value="This payload is returned to client" doc:name="Set Payload" doc:id="2ab7bb3e-3943-4da1-9c54-c76907348924" />
</flow>

</mule> 

Target Variable in Mule-4 connector

 Significance of Target Variable in Mule-4 Connector:


This article explains about Target variable in Mule-4 connector. Target Variable is used to store the contents of service call. In earlier versions of Mule, Message Enricher component need to used to achieve this. This process is extremely simplified by introducing the target variable to the connector in Mule -4.

Let me explain this functionality with an example:

 


The example contains two flows Flow-1 and Flow-2. Flow-1 flow as VM publish-Consume endpoint
that invokes the VM listener of flow-2. once the Flow-2 finishes its execution, the payload return to Flow-1 and it replaces the existing payload of Flow-1, so the existing flow-1 payload vanishes.

Collecting the response from Flow-2 to a Variable rather than replacing it to the existing payload is a great idea, it simplifies the developer life to a greater extent. to achieve the similar functionality in Mule earlier versions there are 2 options.
a) Use Message Enricher scope to configure such calls
b) Save the current payload to a variable before calling Service, after the service call, the ,existing payload is replaced by service call payload, Override the service call payload with payload stored in variable.

Code without Target variable :
<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd">
<vm:config name="VM_Config" doc:name="VM Config" doc:id="eaa6afe4-3cbf-4de0-b904-449c354a92e9" >
<vm:queues >
<vm:queue queueName="myqueue" />
</vm:queues>
</vm:config>
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="08907f91-2a21-434c-96d0-eaa5840ba384" >
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<flow name="Flow-1" doc:id="6ebd4e1b-2cdb-4ad2-ba9b-08ef2663f947" >
<http:listener doc:name="Listener" doc:id="05a7dd8e-b363-4153-83bd-f33f8cac1dd3" config-ref="HTTP_Listener_config" path="/"/>
<set-payload value="payload set in main flow" doc:name="Set Payload" doc:id="a94833c0-2de2-4c18-ad89-d3ddac7ca487" />
<vm:publish-consume doc:name="Publish consume" doc:id="81ab6415-d9e0-4c74-af9f-3361c1abd485" config-ref="VM_Config" queueName="myqueue"/>
<logger level="INFO" doc:name="Logger" doc:id="32d83206-906f-493d-ba8f-3fbfc8342e53" message="After VM call  #[payload]  #[vars.flow2Value_variable]"/>
</flow>
<flow name="Flow-2" doc:id="50f343ec-bbb4-48d5-99e5-05383f3ceb06" >
<vm:listener queueName="myqueue" doc:name="Listener" doc:id="f8618bee-2005-4966-ae8b-da8ede2d367a" config-ref="VM_Config"/>
<set-payload value="payload set in VM flow" doc:name="Set Payload" doc:id="2f3a59df-2748-45e8-8ba7-2f543d2ee7ba" />
</flow>
</mule>


Logger Statement. showing the payload returned from Flow-2:
.LoggerMessageProcessor: After VM call  payload set in VM flow  null


Target Variable configuration:
<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd">
<vm:config name="VM_Config" doc:name="VM Config" doc:id="eaa6afe4-3cbf-4de0-b904-449c354a92e9" >
<vm:queues >
<vm:queue queueName="myqueue" />
</vm:queues>
</vm:config>
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="08907f91-2a21-434c-96d0-eaa5840ba384" >
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<flow name="Flow-1" doc:id="6ebd4e1b-2cdb-4ad2-ba9b-08ef2663f947" >
<http:listener doc:name="Listener" doc:id="05a7dd8e-b363-4153-83bd-f33f8cac1dd3" config-ref="HTTP_Listener_config" path="/"/>
<set-payload value="payload set in main flow" doc:name="Set Payload" doc:id="a94833c0-2de2-4c18-ad89-d3ddac7ca487" />
<vm:publish-consume doc:name="Publish consume" doc:id="81ab6415-d9e0-4c74-af9f-3361c1abd485" config-ref="VM_Config" queueName="myqueue" target="flow2Value_variable"/>
<logger level="INFO" doc:name="Logger" doc:id="32d83206-906f-493d-ba8f-3fbfc8342e53" message="After VM call  #[payload]  #[vars.flow2Value_variable]"/>
</flow>
<flow name="Flow-2" doc:id="50f343ec-bbb4-48d5-99e5-05383f3ceb06" >
<vm:listener queueName="myqueue" doc:name="Listener" doc:id="f8618bee-2005-4966-ae8b-da8ede2d367a" config-ref="VM_Config"/>
<set-payload value="payload set in VM flow" doc:name="Set Payload" doc:id="2f3a59df-2748-45e8-8ba7-2f543d2ee7ba" />
</flow>
</mule>

Logger Statement. showing the  existing payload and  target variable
.LoggerMessageProcessor: After VM call  payload set in main flow  payload set in VM flow

Securing APIs: Two Ways to apply policies for CloudHub applications | With and Without Creating Proxy Applications

 Note: Anypoint Platform’s API Manager policies can only be applied to the applications which are deployed to CloudHub. For other deployment modes you need to have other ways of applying policies.


This article helps you to apply policies via Anypoint Platform’s API Manager.


We have 2 ways to apply policies:

  1. Creating Proxy APIs

  2. Without Creating Proxy APIs


The main difference between the two of them is:

  • Using API ID in Auto-Discovery of your “actual” application,

  • Or Mule itself will create a Proxy application on top of your “actual” application which has API Auto-Discovery.



1) Without Creating Proxy API


We will need these two things:

  1. API ID generated in API Manager and used in the global element “Auto-Discovery” of your application.

  2. Anypoint Platform’s Client ID and Client Secret. We can get them from “Access Management” Under Environments Tab > Choose the environment in which your application is getting deployed. Use them in Runtime properties while deploying the application in below way:

anypoint.platform.client_id : xxxxxxxxxxxx
anypoint.platform.client_secret : xxxxxxxxxxxx

With the help of these two steps, we can now see in API Manager that the status of our API will turn from “Unregistered” to “Active”.


Step 1: Design a RAML, publish the asset to Exchange, import the RAML to Anypoint Studio, and generate the flows.


Step 2: Go to API Manager, Click on Manage API and choose “Manage API from Exchange”.



Step 3: Select your API, and select the managing type as “Basic Endpoint”. Don’t forget to check the box “Mule version: Check this box if you are managing this API in Mule 4 or above.”


Click on Save.




Step 4: Go to the Application in Anypoint Studio, Create a Global Element Auto-Discovery and Add API id and choose the flow name (usually Main flow where the request listens).



Step 5: Go to Access Management (the owner of the account can have access and can view this option. If you are not seeing this, that means you need to request access to the owner of the Anypoint Platform account). Choose the Environments Tab and select your environment. Get your Client ID and Client Secret.




Step 6: Go to Runtime Manager and add the Runtime properties like below and deploy.



Now your API in API manager status will turn to Active and you can start applying policies by going to Policies > Apply New Policy.


Note: There’s no need to restart the application once the policy is applied. It will reflect within seconds automatically. Even if you add one or more policies at a later point of time, no restart of the application is required.



2) Creating Proxy API


In the previous method there were a lot of manual processes required. To avoid all these, we can go for this second approach to create a Proxy application.


This Proxy application is nothing but a kind of wrapper to your main application. Now for each application, we will have 2 apps in Runtime Manager:

  1. Your Actual Application

  2. Your Proxy Application, which has API ID, Client ID, and Client Secret within it. There’s no manual effort required to deploy. It’s deployed from the API manager.


Step 1: Design a RAML, publish the asset to Exchange, import the RAML to Anypoint Studio, and generate the flows.


Step 2: Go to API Manager, Click on Manage API and choose “Manage API from Exchange”.


Step 3: Select your API, and select the managing type as “Endpoint with Proxy”. Don’t forget to check the box “Mule version: Check this box if you are managing this API in Mule 4 or above.” Click on Save.


Step 4: Give the Implementation URL of your actual application that is deployed.


Make sure you provide your complete path, up until /api (all RAML-generated flows have a common base path as /api)


E.g.

http://myfirstapp.cloudhub.io/api

Once done, click on Save.



Step 5: Now you can see the Deployment Configuration. Choose the runtime and name of the Proxy app you want to give and click on deploy. The application will be deployed in the Runtime Manager.



Step 6: Now edit the Consumer endpoint in API Manager with your Proxy endpoint. So that all the requests will hit the proxy application. Basically your implementation URL is your actual endpoint and Consumer endpoint is the endpoint for the Proxy. In other words, the client hits the Proxy endpoint, which in-turn is routed to the implementation URL.



You can see that the Client ID and Client Secret values are picked automatically and placed in Runtime properties. You can also download the jar of the Proxy application and import it in Anypoint Studio, where you can see the API ID is automatically configured and the HTTP request will route to your main app.


You have to provide the endpoint of the Proxy application to consumers/clients so that they don’t have access to your main app. The policies are applied to your Proxy application.


But the thing here is, we need additional vCore and workers to deploy our Proxy app.


According to your requirements, you can choose which method you want to follow to apply policies for your CloudHub apps.



Pros and Cons


Without Proxy Application:

  1. You will save a vCore and worker.

  2. As a developer, you need to know the Client ID and Client Secret - unless the deployment is managed by CI/CD process.

  3. You need to manually create a global element to invoke Auto-Discovery.

  4. You will expose your actual endpoint to the Client/Consumer.

  5. Use case: If your APIs are used within the organization, within intranet, you can choose this option where we can share the endpoints directly. This saves vCores.


With Proxy Application:

  1. You will need additional vCore and worker for each Proxy app you deploy.

  2. As a developer, you don’t need to know the Client ID since it’s managed internally.

  3. No need for the manual process of using API ID or using Client ID and Client Secret.

  4. You will expose your Proxy endpoint over the actual endpoint to the Client/Consumer.

  5. Use case: If your APIs are used outside of your organization, you can choose this option where we can share the endpoints of the Proxy app instead of the actual endpoint. This gives you more security.



These are 2 simple ways to apply policies!