Transformation
Use the JSON Transformation Policy to modify payload structure, query parameters, headers, and formats during request and response processing. This helps you adapt client requests and target API responses without custom middleware.
Overview
The JSON Transformation Policy enables you to modify API request and response payloads dynamically as they pass through API Gateway. Use it to control data formatting, adapt back-end responses to client requirements, or transform client requests before they reach target APIs.
Capabilities
The JSON Transformation Policy provides these data manipulation capabilities:
- Property deletion to remove specific fields from JSON payloads
- Default value addition to ensure required properties exist with fallback values
- Complete restructuring to build new JSON documents from existing data
- Query parameter mapping to set URL query parameters from payload values
- Header manipulation to set request or response headers from payload data
- Combined operations to run deletions, default values, and transformations in a single policy
- Handlebars transformation support for conditional logic, loops, and mathematical operations
- Format conversion, such as transforming JSON to XML and XML to JSON
- Built-in helpers for string manipulation, math operations, and data access
Who this affects
This policy applies to these roles:
- IONAPI-Admin users who configure and manage API Gateway policies
- Integration developers who design API workflows and API flows
Business benefits
Simplified integration
Use transformation policies to reduce the need for custom integration logic.
- Eliminate the need for custom code to reformat API responses
- Connect systems with different data structures without middleware
- Reduce payload size by removing unnecessary data
Enhanced flexibility
Use transformations to align payload formats across different systems.
- Adapt legacy API responses to modern client expectations
- Standardize data formats across multiple back-end services
- Add default values to help keep response structures consistent
Improved performance
Use transformations to reduce payload size and client-side work.
- Reduce bandwidth usage by deleting unused properties
- Minimize client-side processing by pre-formatting data
- Consolidate multiple transformation operations into a single policy execution
Restrictions
JSON Transformation Policy behavior is subject to these restrictions:
- Payload size is limited to 10 MB
- In the request flow, transformations apply only to HTTP methods that include a request body
- In the response flow, transformations apply to all HTTP methods
- Apply transformation policies at the endpoint level
The deletion and addition sequence follows these rules:
- All deletions occur before default value additions and transformations
- If a deletion path refers to a property, object, or array element that does not exist, the delete operation is ignored
- If an addition path refers to a property, object, or array element that does not exist, the resulting property value is
undefined
The policy uses JSONPath expressions to identify elements in JSON documents. JSONPath is a query language similar to XPath for XML. Use it to select objects, properties, and array elements precisely.
Configuration
Use these sections to define the policy XML and understand supported elements and attributes.
Basic configuration
All transformation policies use the same XML structure with three optional sections.
<jsonTransform name="policy_name" displayName="Display Name"
enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<deletions>
<!-- Delete operations -->
</deletions>
<defaultValues>
<!-- Default value additions -->
</defaultValues>
<transformations>
<!-- Transformation templates -->
</transformations>
</jsonTransform>
Policy attributes
| Name | Default | Required | Description |
|---|---|---|---|
| name | n/a | yes | Name of this policy instance. |
| displayName | Display name of this policy instance. | ||
| enabled | true | yes | Indicates whether the policy is enabled. If the policy is not enabled, API Gateway ignores it. |
| version | 1.0 | yes | Version of the policy. |
Elements
| Element | Parent | Required | Type | Multiplicity |
|---|---|---|---|---|
| deletions | <jsonTransform> | no | Container of 0..* <delete> child elements | 0..1 |
| defaultValues | <jsonTransform> | no | Container of 0..* <default> child elements | 0..1 |
| transformations | <jsonTransform> | no | Container of 0..* <transform> child elements | 0..1 |
<delete> element
Zero or more <delete> elements can appear under the <deletions> element.
| Name | Type | Required | Description |
|---|---|---|---|
| path | attribute, string | yes | JSONPath of the object, property, or array item in the document to delete. |
<default> element
Zero or more <default> elements can appear under the <defaultValues> element.
| Name | Type | Required | Description |
|---|---|---|---|
| path | attribute, string | yes | JSONPath of the object, property, or array item to check for existence and create if it does not exist. |
| (element value) | string | yes | Number, true or false, string, or JSON sub-object enclosed in a <![CDATA[ ... ]]> wrapper. |
<transform> element
Zero or more <transform> elements can appear under the <transformations> element.
| Name | Type | Required | Description |
|---|---|---|---|
| kind | attribute, string | no | Transformation engine. Values are handlebars or jsonpathObjectTransform. If omitted, the default is jsonpathObjectTransform. |
| output | attribute, string | no | Value to use for the response content-type header. If omitted, API Gateway preserves the content type returned by the target. |
| n/a | CDATA string | yes | Template that describes how to build a new document from the original document. |
Examples
The examples use these sample inputs.
Sample inputs
Sample input 1
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 199.95,
"size": "24-inch",
"safetyRated": true,
"features": {
"style": "mountain",
"brakes": "disc"
}
}
}
}
Sample input 2
{
"ErrorList": null,
"Status": 1,
"UserDetailList": [
{
"Email": "john.doe@example.com",
"FirstName": "John",
"LastName": "Doe",
"UserId": 3216,
"Status": 100
},
{
"Email": "jane.smith@example.com",
"FirstName": "Jane",
"LastName": "Smith",
"UserId": 3228,
"Status": 100
}
]
}
Delete unnecessary properties
Use deletions to reduce payload size by removing data that clients do not need.
Example scenario: Your back-end returns detailed product information, but mobile clients need only basic details.
Input payload: Sample input 1
Policy configuration
<jsonTransform continueOnError="false" displayName="jsonTransform_policy_transform"
enabled="true" name="JSONTranform" version="1"
xmlns="http://www.infor.com/ion/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<deletions>
<delete path="$.store.book[1..2].price"/>
<delete path="$.store.bicycle.color"/>
</deletions>
</jsonTransform>
Result
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"price": 199.95,
"size": "24-inch",
"safetyRated": true,
"features": {
"style": "mountain",
"brakes": "disc"
}
}
}
}
The second and third book prices are removed, along with the bicycle color property.
Add default values
Use default values to create missing properties required by your API contract.
Example scenario: Your API contract requires contact information for all products, but legacy systems do not include this data.
Input payload: Sample input 1
Policy configuration
<jsonTransform continueOnError="false" displayName="jsonTransform_policy_transform"
enabled="true" name="JSONTranform" version="1"
xmlns="http://www.infor.com/ion/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<deletions/>
<defaultValues>
<default path="$.store.bicycle.terms.warranty">1 year parts and labor</default>
<default path="$.store.bicycle.contactInfo">
<![CDATA[JSON{"email": "sales@infor.com", "phone": "678-319-8000"}]]>
</default>
</defaultValues>
</jsonTransform>
Result
{
"store": {
"book": [
...
],
"bicycle": {
"color": "red",
"price": 199.95,
"size": "24-inch",
"safetyRated": true,
"features": {
"style": "mountain",
"brakes": "disc"
},
"terms": {
"warranty": "1 year parts and labor"
},
"contactInfo": {
"email": "sales@infor.com",
"phone": "678-319-8000"
}
}
}
}
Combine multiple operations
Combine deletions, default values, and transformations in one policy.
All deletions run before default value additions and transformations.
Example scenario: Remove specific fields, add missing fields, and create a new response structure in a single policy.
Input payload: Sample input 1
Policy configuration
<jsonTransform continueOnError="false" displayName="jsonTransform_policy_transform"
enabled="true" name="JSONTranform" version="1"
xmlns="http://www.infor.com/ion/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<deletions>
<delete path="$.store.book[1].price"/>
</deletions>
<defaultValues>
<default path="$.store.bicycle.contactInfo">
<![CDATA[JSON{"email": "sales@infor.com", "phone": "678-319-8000"}]]>
</default>
</defaultValues>
<transformations>
<transform><![CDATA[{
"allPrices": ["$.store..price"],
"contact": "$.store.bicycle.contactInfo",
"book3": "$.store.book[2]"
}]]></transform>
</transformations>
</jsonTransform>
Result
{
"allPrices": [8.95, 8.99, 22.99, 199.95],
"contact": {
"email": "sales@infor.com",
"phone": "678-319-8000"
},
"book3": {
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}
}
Set query parameters from payload data
Map payload values to URL query parameters for the target API call.
Example scenario: The target API expects query parameters, but the client sends a JSON body.
Policy configuration
<jsonTransform name="query_param_example" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars"><![CDATA[
{{SetReqQuery 'cl' (jsonPathValue '$.creditLimit')}}
{{SetReqQuery 'cust' (jsonPathValue '$.customer')}}
]]></transform>
</transformations>
</jsonTransform>
Notes:
- Use request headers as query parameters, for example
{{SetReqQuery 'data' (requestVars 'request.header.some-data')}}. - Use existing query parameters, for example
{{SetReqQuery 'newParam' (requestVars 'request.queryparam.existingParam')}}.
Set headers from payload data
Set or modify HTTP headers based on request or response payload values.
Example scenario: The target API requires a value in a header, but the client provides it in the JSON payload.
Policy configuration
<jsonTransform name="header_example" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars"><![CDATA[
{{SetReqHeader 'credit-limit' (jsonPathValue '$.creditLimit')}}
{{SetReqHeader 'wilma' (requestVars 'request.header.fred')}}
]]></transform>
</transformations>
</jsonTransform>
Use SetResHeader in response-side transformations to set headers that clients receive, for example {{SetResHeader 'X-Custom-Header' 'custom-value'}}.
SetReqQuery, SetReqHeader, or SetResHeader, ensure it also outputs a request or response payload. Otherwise, the transformation can return an empty payload.
Nest Handlebars helpers. The inner helper runs first and its result is passed to the outer helper, for example {{uppercase (requestVars 'request.header.content-type')}}.
Advanced transformations with Handlebars
The Handlebars transformation engine supports complex data manipulation, conditional logic, and format conversion. Use kind="handlebars" to access these capabilities.
Transform JSON to XML
Convert JSON responses to XML for legacy systems or client requirements.
Example scenario: Your back-end returns JSON, but a legacy client requires XML.
Input payload: Sample input 2
Policy configuration
<jsonTransform name="json_to_xml" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars" outputType="application/xml"><![CDATA[
<?xml version="1.0" encoding="utf-8"?>
<result>
{{#if ErrorList}}
<errors>
{{#each ErrorList}}
<error>{{this}}</error>
{{/each}}
</errors>
{{else}}
<users count="{{length UserDetailList}}">
{{#each UserDetailList}}
<user>
{{#if @first}}<first/>{{/if}}
<itemNo>{{@index}}</itemNo>
<id>{{UserId}}</id>
<fullName>{{FirstName}} {{uppercase LastName}}</fullName>
<email>{{Email}}</email>
</user>
{{/each}}
</users>
{{/if}}
</result>]]></transform>
</transformations>
</jsonTransform>
Result
<?xml version="1.0" encoding="utf-8"?>
<result>
<users count="2">
<user>
<first/>
<itemNo>0</itemNo>
<id>3216</id>
<fullName>John DOE</fullName>
<email>john.doe@example.com</email>
</user>
<user>
<itemNo>1</itemNo>
<id>3228</id>
<fullName>Jane SMITH</fullName>
<email>jane.smith@example.com</email>
</user>
</users>
</result>
Key Handlebars features used:
{{#if}}and{{else}}for conditional output based on whetherErrorListexists{{#each}}to loop throughUserDetailList{{@index}}to access the current iteration index (0-based){{@first}}to check whether this is the first item{{length}}to get the item count{{uppercase}}to convert text to uppercase
Transform XML to JSON
Convert XML responses from legacy systems to JSON for modern clients.
Example scenario: Your back-end SOAP service returns XML, but REST clients require JSON.
Sample input (XML)
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ListResponse xmlns="http://www.infor.com/businessinterface/Item_v3">
<ListResponse>
<DataArea>
<Item_v3>
<description>raw material 01</description>
<itemCode>000025</itemCode>
<itemGroup>100000</itemGroup>
<itemType>purchase</itemType>
</Item_v3>
<Item_v3>
<description>Equipment Group 1</description>
<itemCode>001</itemCode>
<itemGroup>800000</itemGroup>
<itemType>equipment</itemType>
</Item_v3>
</DataArea>
</ListResponse>
</ListResponse>
</S:Body>
</S:Envelope>
Policy configuration
<jsonTransform name="xml_to_json" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars" outputType="application/json"><![CDATA[
{{#with S:Envelope.S:Body.ListResponse.ListResponse.DataArea}}
[
{{#each Item_v3}}
{
"itemGroup": "{{itemGroup}}",
"itemType": "{{itemType}}",
"itemCode": "{{itemCode}}",
"description": "{{description}}"
}{{#if @last}}{{else}},{{/if}}
{{/each}}
]
{{/with}}]]></transform>
</transformations>
</jsonTransform>
Result
[
{
"itemGroup": "100000",
"itemType": "purchase",
"itemCode": "000025",
"description": "raw material 01"
},
{
"itemGroup": "800000",
"itemType": "equipment",
"itemCode": "001",
"description": "Equipment Group 1"
}
]
Key features used:
{{#with}}to set context for nested operations{{@last}}to avoid trailing commas in JSON output- Namespace-prefixed element access, such as
S:Envelope
Use mathematical and statistical helpers
Perform calculations during transformation without requiring client-side processing.
Example scenario: Generate summary statistics from numeric values.
Input payload: Sample input 1
Policy configuration
<jsonTransform name="math_helpers" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api math_helpers.xsd">
<transformations>
<transform kind="handlebars"><![CDATA[{
"statistics": {
"total": "{{sum (jsonPath '$.store..price')}}",
"minimum": "{{min (jsonPath '$.store..price')}}",
"maximum": "{{max (jsonPath '$.store..price')}}",
"average": "{{avg (jsonPath '$.store..price')}}",
"median": "{{median (jsonPath '$.store..price')}}"
}
}]]></transform>
</transformations>
</jsonTransform>
Result
{
"statistics": {
"total": "253.87",
"minimum": "8.95",
"maximum": "199.95",
"average": "50.774",
"median": "12.99"
}
}
Available mathematical helpers include sum, min, max, avg, median, and mode.
Access request and response context
Use context variables to access request headers, query parameters, and user information during transformation.
Example scenario: Include request metadata in a transformed response.
Policy configuration
<jsonTransform name="context_access" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars"><![CDATA[{
"metadata": {
"requestedBy": "{{requestVars 'context.user.Identity2'}}",
"contentType": "{{uppercase (requestVars 'request.header.content-type')}}",
"origin": "{{requestVars 'request.header.origin'}}",
"queryParam": "{{requestVars 'request.queryparam.filter'}}",
"responseStatus": "{{responseVars 'response.status'}}"
}
}]]></transform>
</transformations>
</jsonTransform>
Result
{
"metadata": {
"requestedBy": "0d0017e0-40dc-459d-a841-df0d71fa0b4e",
"contentType": "APPLICATION/JSON",
"origin": "https://mingle-t20-ionapiapplication.mingle.inforos.dev.inforcloudsuite.com",
"queryParam": "",
"responseStatus": "200"
}
}
Use requestVars to access request data and responseVars to access response data. Nest helpers, for example {{uppercase (requestVars 'request.header.content-type')}}.
Store and reuse values with variables
Store intermediate values during transformation and reuse them later in the template.
Example scenario: Count items during iteration and use the count in the output.
Input payload: Sample input 2
Policy configuration
<jsonTransform name="variables_example" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars" outputType="application/xml"><![CDATA[
<result>
<items>
{{#each UserDetailList}}
<item>{{Email}}</item>
{{var 'itemCount' @index}}
{{/each}}
</items>
<summary>
<totalProcessed>{{sum itemCount 1}}</totalProcessed>
<allStatuses>{{sum (jsonPath '$.UserDetailList..Status')}}</allStatuses>
</summary>
</result>]]></transform>
</transformations>
</jsonTransform>
Result
<result>
<items>
<item>john.doe@example.com</item>
<item>jane.smith@example.com</item>
</items>
<summary>
<totalProcessed>2</totalProcessed>
<allStatuses>200</allStatuses>
</summary>
</result>
Modify the target URL path
Adjust the target API endpoint URL during request processing.
Example scenario: Remove the last path segment before calling the target.
Policy configuration
<jsonTransform name="url_modification" enabled="true" version="1"
xmlns="http://www.infor.com/ion/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.infor.com/ion/api jsonTransform.xsd">
<transformations>
<transform kind="handlebars"><![CDATA[
{{trimUrlPath}}
]]></transform>
</transformations>
</jsonTransform>
This helper modifies the target URL path. Use it in requests without a payload because it does not change the request body.
Handlebars helper reference
This section lists common Handlebars helpers used in transformations.
Iteration and conditionals
- Use
{{#each collection}}to loop through arrays or objects. - Special values include
{{@index}},{{@first}},{{@last}}, and{{this}}. - Use
{{#if condition}}and{{else}}for conditional output. - Use
{{#with object}}to set context for nested operations.
String operations
{{uppercase text}}{{lowercase text}}{{length string}}
Data access
{{jsonPath 'expression'}}{{requestVars 'path'}}{{responseVars 'path'}}{{var 'name' value}}
Mathematical operations
{{sum values}}{{min values}}{{max values}}{{avg values}}{{median values}}{{mode values}}
Gateway operations
{{SetReqQuery 'name' value}}{{SetReqHeader 'name' value}}{{SetResHeader 'name' value}}{{trimUrlPath}}
Additional information
Use these sections for background details, operational notes, and planning guidance.
Transformation types
The policy supports two transformation engines specified by the kind attribute.
jsonpathObjectTransformis the default and is suited to restructuring JSON using JSONPath expressions.handlebarsis required for helpers such asSetReqQuery,SetReqHeader, andSetResHeader.
Example
<transform kind="handlebars" output="application/xml">
{{SetReqQuery 'param' 'value'}}
</transform>
Output content type
Use the output attribute to change the response content-type header when you transform formats. If omitted, API Gateway preserves the content type returned by the target.
Error handling
Use the continueOnError attribute to control failure behavior.
falsestops processing and returns an error if the transformation fails.truecontinues processing and passes through the original payload if the transformation fails.
Performance considerations
Use deletions to reduce payload size and improve network and client performance. Complex JSONPath expressions and large payload transformations can increase latency, so test with realistic data volumes.
Policy placement
Apply the JSON Transformation Policy in these stages:
- Request flow, before the target API call
- Response flow, after the target API call
Interaction with other policies
Consider the combined effect of endpoint and suite policies when you add a transformation policy.
Example
<!-- Transformation reads 'fred' header -->
{{SetReqHeader 'wilma' (requestVars 'request.header.fred')}}
<!-- Header policy removes 'fred' header -->
<removeHeader name="fred"/>