Write a MuleSoft API Custom Policy to copy one HTTP header to another.

 The blog helps you to start writing a MuleSoft API Custom Policy. This will help you to copy a HTTP header to another.

 Mulesoft, API Hub, API Policy

  Mulesoft    |      Anupam Chakraborty    |      Nov 05 2023 03:25 AM

 Login to Like      Login to Follow      1514 Views

Introduction


In general, we are ok with all the Out of the box policies that is provided by MuleSoft and uses them in our API. However, there are times when we might have to do something custom. In this case, my ask is to copy over a header to another header.

Say http header           firstName: Anupam

Will get copied to        people: firstName=Anupam


Get Started


The first step like other Custom MuleSoft object is to create a skeleton based on an archetype. To do that, we would need to connect to the Maven Central repository. This is what we need to add to the settings.xml file.


<profiles>
<profile>
<id>archetype-repository</id>
<repositories>
<repository>
<id>archetype</id>
<name>Mule Repository</name>
<url>https://repository.mulesoft.org/nexus/content/repositories/public</url>
<releases>
<enabled>true</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>

Once the maven is configured, we would go to a new directory that we will use. We will go to the directory in command line and execute the following command

mvn -Parchetype-repository archetype:generate \
-DarchetypeGroupId=org.mule.tools \
-DarchetypeArtifactId=api-gateway-custom-policy-archetype \
-DarchetypeVersion=1.2.0 \
-DgroupId=${orgId} \
-DartifactId=header-manipulation-policy\
-Dversion=1.0.0 \
-Dpackage=mule-policy


Replace the ${orgId} with the Anypoint Platform Organization Id where the policy will be uploaded.

Before finishing, Maven asks you to set up:

  • policyDescription: A brief description of your policy.
  • policyName: The identifier name of your policy.
A screenshot of a computer program

Description automatically generated


After running the command, the project’s directory will have a structure similar to:


A screenshot of a computer program

Description automatically generated


The pom.xml will have the following sections:

  • groupId: same as the organization ID defined above.
  • Packaging: mule-policy so packager plugin knows what to build.
  • dependencies: We will add dependency of the http-policy-transform-extension
  • distributionManagement: section is defined pointing to user's Exchange.
  • mule-maven-plugin: responsible of packaging the policy into a deployable jar
  • maven-deploy-plugin: configured to deploy both the resulting jar and the YAML when uploading the policy to Exchange


The actual implementation

Now that we have the skeleton ready from the archetype there are 2 main files we are most interested in. They are a YAML file that has the same name as the name of your project and the template.xml file.

So we would first head over to the header-manipulation-policy.yaml file. This YAML file provides information about the policy and its requirements. The YAML file is not tied to any specific runtime or binary. This YAML files also help us define the input parameter required by the policy.


Here is the file in our case.


id: header-manipulation-policy
name: Header Manipulation Policy
description: Custom API Policy for Header Manipulation
category: Custom
type: custom
resourceLevelSupported: true
encryptionSupported: false
standalone: true
requiredCharacteristics: []
providedCharacteristics: []
configuration:
- propertyName: requestHeaderMapping
name: Mapping to Update Request Headers
description: Dataweave expression that will be evaluated to update request headers.
type: keyvalues
optional: true
sensitive: false
allowMultiple: true

- propertyName: responseHeaderMapping
name: Mapping to Update Response Headers
description: Dataweave expression that will be evaluated to update response headers.
type: expression
optional: true
sensitive: false
allowMultiple: true


This can be visualized as here.

A screenshot of a computer

Description automatically generated


As you can see there is a Mapping to update Request headers and a mapping to update response headers.

In our case, we will map as follow

KeyValue
people

#[if(!isEmpty(attributes.headers."firstName")) 

("FirstName " ++ attributes.headers."firstName") else null]


Now let us get into the actual code. The template.xml


Here is the simple code for the same.


<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http-policy="http://www.mulesoft.org/schema/mule/http-policy"
xmlns:http-transform="http://www.mulesoft.org/schema/mule/http-policy-transform" 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-policy http://www.mulesoft.org/schema/mule/http-policy/current/mule-http-policy.xsd
http://www.mulesoft.org/schema/mule/http-policy-transform http://www.mulesoft.org/schema/mule/http-policy-transform/current/mule-http-policy-transform.xsd">

<http-policy:proxy name="header-manipulation">
<http-policy:source propagateMessageTransformations="true">
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='Header Manipulation Policy Execution Start' />
{{#if requestHeaderMapping}}
<try>
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='Request header injection config present' />
{{#each requestHeaderMapping}}
<set-variable variableName="thisKey" value="{{{this.key}}}"/>
<set-variable variableName="thisValue" value="{{{this.value}}}"/>
<choice>
<when expression="#[!(isEmpty(vars.thisValue))]">
<http-transform:add-request-headers-list>
<http-transform:new-headers>
<http-transform:header headerName="{{{this.key}}}" headerValue="#[vars.thisValue]"/>
</http-transform:new-headers>
</http-transform:add-request-headers-list>
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='#["Request Header injected for " ++ vars.thisKey]' />
</when>
<otherwise>
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='#["Value is not present. Request Header injection skipped for " ++ vars.thisKey]' />
</otherwise>
</choice>
{{/each}}
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='All Request header injection completed' />
<error-handler>
<on-error-continue type="EXPRESSION">
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='{{{this.value}}} is not present. Request Header injection skipped' />
</on-error-continue>
</error-handler>
</try>
{{/if}}
<http-policy:execute-next/>
{{#if responseHeaderMapping}}
<try>
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='Response header injection config present' />
{{#each responseHeaderMapping}}
<set-variable variableName="thisKey" value="{{{this.key}}}"/>
<set-variable variableName="thisValue" value="{{{this.value}}}"/>
<choice>
<when expression="#[!(isEmpty(vars.thisValue))]">
<http-transform:add-response-headers-list>
<http-transform:new-headers>
<http-transform:header headerName="{{{this.key}}}" headerValue="#[vars.thisValue]"/>
</http-transform:new-headers>
</http-transform:add-response-headers-list>
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='#["Response Header injection complete for " ++ vars.thisKey]' />
</when>
<otherwise>
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='Value is not present. Response Header injection skipped' />
</otherwise>
</choice>
{{/each}}
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='All Response header injection completed' />
<error-handler>
<on-error-continue type="EXPRESSION">
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='Value is not present. Response Header injection skipped' />
</on-error-continue>
</error-handler>
</try>
{{/if}}
<logger level="DEBUG" category="org.mule.runtime.core.internal.processor.LoggerMessageProcessor" message='Header Manipulation Policy Execution Complete' />
</http-policy:source>
</http-policy:proxy>
</mule>


And that is it. We are good to go. Now we need to deploy the application to Exchange to view it in the API Manager.


To deploy, we will use a simple two maven command from the command line


mvn clean install
mvn clean deploy -s settings.xml -DskipTests

This can be easily converted into CI/CD based on the tool you would use.

Conclusion

This is a simple blog to create your own custom MuleSoft Policy. Please let me know your thoughts. Let me know if you think there is a custom policy that you would want my help to create here.


Comments:

Leave a Comment:

Please login to post comment into this page.

Please login to submit a new Blog.