IBM API Connect Tutorial: Part-2 IBM APIC Map Policy with example

IBM API Connect Tutorial: Part-2 IBM APIC Map Policy with example

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:

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




	
		
			Mohammed
			street1
			city1
			state1
			123456
		
		
			Ahmed
			street2
			city2
			state2
			654321
		
		
			11111
			N
			USD
			
			
		
		
			
				01
				1
				Active
				20.00
				2.00
				description1
				SUPPL1
			
			
				02
				2
				Active
				21.50
				1.00
				description2
				SUPPL2
			
			
				03
				2
				Cancelled
				31.00
				1.00
				description3
				SUPPL3
					
			
				04
				1
				Rejected
				30.00
				1.00
				description4
				SUPPL4
					
			
				05
				1
				Not_picked
				30.00
				1.00
				description4
				SUPPL4
				
		
	
                         

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:
Mocking the legacy web service
Modernized API

The modernized API will return order data in JSON format. We’ll use below format in our example. :

{
     "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:

Mapping document

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.

Define the response object variable

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.

Map policy

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.

Define input structure

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

Input structure of map policy

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

Map policy

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.

Define output structure

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

Input and Output structure in map policy
  • 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:

 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:

  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.

 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. :

 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:

IBM API Mapping Policy

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.

Run the API using Postman

The transformed API response is as below:

{
     "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

258

8 Responses

  1. Ali Elorabi
    July 4, 2021
  2. Stanley
    December 30, 2021
  3. Stanley
    January 3, 2022
    • Sadruddin Md
      January 5, 2022
  4. Anuj
    April 20, 2022
  5. anuj
    April 20, 2022

Write a response

This site uses Akismet to reduce spam. Learn how your comment data is processed.