Introduction
In this blog, we’ll explore some key features of IBM APIC Map policy. In order for our demonstration, let’s build a use case that covers some use cases ranging from simple to complex.
If you have not already gone through, please take a look at previous blogs on IBM API Connect:
- https://iteritory.com/install-ibm-api-connect-lte-in-local-windows-system/
- https://iteritory.com/ibm-api-connect-tutorial-part-1-develop-your-first-api/
Use Case
In this sample use case, we have an existing legacy web service that that returns the order information in XML format and isn’t standard. We’ll need to modernize this web service. We’ll use IBM APIC to wrap it with a modern REST compliant API. The data format of the new API will be JSON. Let’s take a look at the use case detail:
Legacy Service
Legacy service returns order data in XML format. We’ll use below data in our example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
<?xml version="1.0"?> <orderData> <pOrder orderDate="21-11-2020"> <shippingAddress country="USA"> <name>Mohammed</name> <street>street1</street> <city>city1</city> <state>state1</state> <zip>123456</zip> </shippingAddress> <billingAddress country="USA"> <name>Ahmed</name> <street>street2</street> <city>city2</city> <state>state2</state> <zip>654321</zip> </billingAddress> <orderHeader> <orderNumber>11111</orderNumber> <cancelled>N</cancelled> <currency>USD</currency> <SpecialInstructionCode/> <Remarks/> </orderHeader> <orderLines> <line> <lineNo>01</lineNo> <quantity>1</quantity> <status>Active</status> <unitPrice>20.00</unitPrice> <discountValue>2.00</discountValue> <itemDescription>description1</itemDescription> <supplierCode>SUPPL1</supplierCode> </line> <line> <lineNo>02</lineNo> <quantity>2</quantity> <status>Active</status> <unitPrice>21.50</unitPrice> <discountValue>1.00</discountValue> <itemDescription>description2</itemDescription> <supplierCode>SUPPL2</supplierCode> </line> <line> <lineNo>03</lineNo> <quantity>2</quantity> <status>Cancelled</status> <unitPrice>31.00</unitPrice> <discountValue>1.00</discountValue> <itemDescription>description3</itemDescription> <supplierCode>SUPPL3</supplierCode> </line> <line> <lineNo>04</lineNo> <quantity>1</quantity> <status>Rejected</status> <unitPrice>30.00</unitPrice> <discountValue>1.00</discountValue> <itemDescription>description4</itemDescription> <supplierCode>SUPPL4</supplierCode> </line> <line> <lineNo>05</lineNo> <quantity>1</quantity> <status>Not_picked</status> <unitPrice>30.00</unitPrice> <discountValue>1.00</discountValue> <itemDescription>description4</itemDescription> <supplierCode>SUPPL4</supplierCode> </line> </orderLines> </pOrder> </orderData> |
We’ll use https://www.mockable.io/ to mock the legacy web service that returns above data. Let’s mock the legacy web service by following below steps:
- Open https://www.mockable.io/ in browser. Click on Try Now! button.
- In the next window click on DEFINE A NEW REST MOCK
- In the next window, let’s define the mock service. I have used following configuration on to mock the service:
- Context Type: application/xml
- Response Body: Paste the above XML content.
- Thereafter, save and start the mock. Use URL mentioned in the Path section to invoke mock web service. Take a look at the below sample mocking that I used while writing this article:

Modernized API
The modernized API will return order data in JSON format. We’ll use below format in our example. :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
{ "shipTo": { "name": "Mohammed", "address": "street1, city1, state1, USA", "zip": "123456" }, "orderNo": "11111", "currency": "USD", "billTo": { "name": "Ahmed", "address": "street2, city2, state2, USA" }, "orderDetail": [ { "orderLineNo": "01", "quantity": "1", "unitPrice": "20.00", "discount": "2.00", "description": "description1", "supplierCode": "SUPPL1", "lineStatus": 0 }, { "orderLineNo": "02", "quantity": "2", "unitPrice": "21.50", "discount": "1.00", "description": "description2", "supplierCode": "SUPPL2", "lineStatus": 0 }, { "orderLineNo": "03", "quantity": "2", "unitPrice": "31.00", "discount": "1.00", "description": "description3", "supplierCode": "SUPPL3", "lineStatus": 1 }, { "orderLineNo": "04", "quantity": "1", "unitPrice": "30.00", "discount": "1.00", "description": "description4", "supplierCode": "SUPPL4", "lineStatus": 2 }, { "orderLineNo": "05", "quantity": "1", "unitPrice": "30.00", "discount": "1.00", "description": "description4", "supplierCode": "SUPPL4", "lineStatus": "Not_picked" } ], "orderSummary": { "totalLines": 5, "orderValue": 63, "discount": 3 } } |
Mapping Document
We’ll use below mapping rules while implementing the new modernized wrapper API:

Implement the modernized API
Our goal is to invoke the legacy webservice (mocked above) using invoke policy and then we will use map policy to reformat the legacy response as per the mapping document and finally to produce the reformatted JSON output.
- Build the basic API
Sign in to the API Designer and build a basic API with following details:
Title: Map Policy Demo API
Description: IBM APIC Map Policy Demo API
Base Path: /map-policy-demo-api
Path: Keep the default
Security: Keep the default clientId.
Property: Change the value of target-url to the URL that we generated in https://mockable.io [refer to the previous section]
- Configure the Assembly section
Click on the invoke policy to open the configuration pane on the right. Scroll all the way down and locate Response object variable field. Enter var_resp. This variable will store the response from backend. We’ll reference to this variable from map policy.

Now, drag the Map policy from the left pane. A pop-up window will open. Click on the Pencil icon (highlighted below) to define the input data structure. Thereafter, click on + input button.

A new segment will open up. Populate this as segment as below:
Context variable: var_resp.body [This is the variable that will contain response from our legacy backend. Hence, we are defining it as input segment of map policy]
Content Type: application/xml
Definition: Click on the drop-down list and select inline schema. A new window will open up. Click on Generate from sample XML tab. Paste the XML document that we have above and click on Generate and then Done buttons. We’ll see the configuration something like below.

Click on Done button. You’ll now see that the APIC has created an input data structure from the sample data:

Now, let’s define the output structure. Click on the pencil icon on the output side of the map policy. Thereafter, click on + output button

A new segment will open up. Populate this as segment as below:
Context variable: message.body [This is the output context]
Content Type: application/json
Definition: Click on the drop-down list and select inline schema. A new window will open up. Click on Generate from sample JSONtab. Paste the XML document that we have above and click on Generate and then Done buttons. We’ll see the configuration something like below.

Click on Done button. You’ll now see that the APIC has created an output data structure from the sample data:

- Generic Instruction to configure the Map Policy
To use the map policy, follow the simple rules as mentioned below:
To connect an input field to an output field, click the grey dot (directly on the right) of the input field and then click the grey dot (directly on the left) of the output field. When you do that, a green line is drawn, linking the two input to the output.
You can also connect multiple input to a single output field. Thereafter, to configure the output, simply click on the green dot on the left of the output field, a window will open and you can configure, write gateway script etc.
In below sections, let’s cover some of the complex mapping logics and how those are implemented:
- Mapping of Address field
In the address field, we are concatenating multiple data points from input XML. It’s not that complex. Below is the the YAML snippet with Gatewayscript from the same:
1 2 3 4 5 6 7 8 9 10 11 |
set: output.shipTo.address from: input.orderData.pOrder.shippingAddress.street input.orderData.pOrder.shippingAddress.city input.orderData.pOrder.shippingAddress.state input.orderData.pOrder.shippingAddress.@country value: | $(input.orderData.pOrder.shippingAddress.street) + ", "+ $(input.orderData.pOrder.shippingAddress.city)+", "+ $(input.orderData.pOrder.shippingAddress.state)+", "+ $(input.orderData.pOrder.shippingAddress.@country); |
- Mapping of lineStatus field
For the lineStatus field, we need to execute a logic to check what is the incoming status and accordingly we”ll set the output value. In this particular mapping, you will also see how to use foreach loop in map policy. Below is the the YAML snippet with Gatewayscript from the same:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
create: output.orderDetail foreach: input.orderData.pOrder.orderLines.line from: input.orderData.pOrder.orderLines.line actions: set: orderLineNo from: lineNo set: quantity from: quantity set: unitPrice from: unitPrice set: discount from: discountValue set: description from: itemDescription set: supplierCode from: supplierCode set: lineStatus from: status value: |- var retValue = undefined; if ($(status).toUpperCase() == 'ACTIVE'){ retValue=0; }else if ($(status).toUpperCase() == 'REJECTED'){ retValue=2; }else if ($(status).toUpperCase() == 'CANCELLED'){ retValue=1; }else{ retValue=$(status); } retValue; |
- Mapping of totalLines field
In this field, we are running some logic as well as we counting the total number of order lines. In the code snippet below, you will notice an expression $(0). This expression is basically total accumulated value in the output field. If see below, the for each order line in input message, we are adding +1 to $(0) which keeps on getting accumulated. At the end of the for loop, we get the total number of order lines.
1 2 3 4 |
set: output.orderSummary.totalLines from: input.orderData.pOrder.orderLines.line foreach: input.orderData.pOrder.orderLines.line value: $(0)+1; |
- Mapping of orderValue field
This field mapping is a little more complex where we count the total order value for ACTIVE order lines from the input message.
The modernized API will return order data in JSON format. We’ll use below format in our example. :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
set: output.orderSummary.orderValue foreach: input.orderData.pOrder.orderLines.line from: input.orderData.pOrder.orderLines.line.unitPrice input.orderData.pOrder.orderLines.line.quantity input.orderData.pOrder.orderLines.line.status value: |- var statusValue = $(input.orderData.pOrder.orderLines.line.status).toUpperCase(); if (statusValue === 'ACTIVE'){ +$(0) + $(input.orderData.pOrder.orderLines.line.unitPrice) * $(input.orderData.pOrder.orderLines.line.quantity); }else{ +$(0) + 0; } |
Now that we have completed mapping requirements as per the mapping document, let’s see how the mapping policy looks like:

Test the IBM APIC Map Policy API
Let’s run the API we just implemented above by using the triangular Publish button from the toolkit (if you are not use which button, please check my previous blog https://iteritory.com/ibm-api-connect-tutorial-part-1-develop-your-first-api/) .. This will publish the API in my local test environment.
To test the API, I’ll use POSTMAN tool.

The transformed API response is as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
{ "shipTo": { "name": "Mohammed", "address": "street1, city1, state1, USA", "zip": "123456" }, "orderNo": "11111", "currency": "USD", "billTo": { "name": "Ahmed", "address": "street2, city2, state2, USA" }, "orderDetail": [ { "orderLineNo": "01", "quantity": "1", "unitPrice": "20.00", "discount": "2.00", "description": "description1", "supplierCode": "SUPPL1", "lineStatus": 0 }, { "orderLineNo": "02", "quantity": "2", "unitPrice": "21.50", "discount": "1.00", "description": "description2", "supplierCode": "SUPPL2", "lineStatus": 0 }, { "orderLineNo": "03", "quantity": "2", "unitPrice": "31.00", "discount": "1.00", "description": "description3", "supplierCode": "SUPPL3", "lineStatus": 1 }, { "orderLineNo": "04", "quantity": "1", "unitPrice": "30.00", "discount": "1.00", "description": "description4", "supplierCode": "SUPPL4", "lineStatus": 2 }, { "orderLineNo": "05", "quantity": "1", "unitPrice": "30.00", "discount": "1.00", "description": "description4", "supplierCode": "SUPPL4", "lineStatus": "Not_picked" } ], "orderSummary": { "totalLines": 5, "orderValue": 63, "discount": 3 } } |
Github Link
You can find the API Yaml and the mapping document in the github repo: https://github.com/msadrud/ibm-apic-map-policy
Ali Elorabi
July 4, 2021Good example of map policy
But , if you look at gateway log you can find multiple errors with code 0x88c0005d and message the variable name ‘api.properties.0’ is not a valid identifier
Though , the response of API is as we expect .
Sadruddin Md
July 17, 2021I’ll check this out.
Stanley
December 30, 2021(1) Somehow the mapping is not working.
I copied the entire API Yaml from git, and change target url to my
http://demo9251414.mockable.io/.
(2) I query http://demo9251414.mockable.io/ directly from postman, and was able to get the xml response as expected.
Question: how to debug where the issue is?
Here is the response:
“shipTo”: {
“address”: “undefined, undefined, undefined, undefined”
…..
Sadruddin Md
December 30, 2021Hi Stanley … did you check the DP logs?
Stanley
January 3, 2022Hi Sadruddin,
I got below error. Is there anything missing to setup?
apigw (apiconnect): Map: API=map-policy-demo-api, policy=map : set action lineStatus: invalid value expression and no default configured. {“set”:”lineStatus”,”from”:”status”,”value”:”var retValue = undefined;\nif ($(status).toUpperCase() == ‘ACTIVE’){\n retValue=0;\n}else if ($(status).toUpperCase() == ‘REJECTED’){\n retValue=2;\n}else if ($(status).toUpperCase() == ‘CANCELLED’){\n retValue=1;\n}else{\n retValue=$(status);\n}\nretValue;”}
Thanks,
Stanley
Sadruddin Md
January 5, 2022That’s strange! Please email me the YAML file; I will try and take a look
Anuj
April 20, 2022I am trying to implement an if else condition for array to array mapping inside MAP policy, but not getting desired results, here is the sample code
var statusValue = $(input.d.Item.RefDate);
if (typeof(statusValue) != ‘undefined’ && (statusValue !== null) && (statusValue !== “”) && (statusValue.length !== 0)) {
$(input.d.Item.RefDate);
}
else{
‘else’;
}
anuj
April 20, 2022Hi, I am trying to implement an if else condition in array to array mapping using MAP policy, but not getting desired results, could you advice if I am missing something?
var statusValue = $(input.d.Item.RefDate);
if (typeof(statusValue) != ‘undefined’ && (statusValue !== null) && (statusValue !== “”) && (statusValue.length !== 0)) {
$(input.d.Item.RefDate);
}
else{
‘else’;
}