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

Anupam Chakraborty
5 min readNov 5, 2023

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

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.

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

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.

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

Key: people

Value: #[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. For more such blogs please visit https://www.wedointegration.com/

--

--

Anupam Chakraborty

Solution Architect — API / Mulesoft / Dell Boomi / AWS / SAP PI. Dell Boomi and Mulesoft Certified.