Apply compression to a mocked response - azure-api-management

Is it possible to apply compression (gzip) to a mocked response? Or is it limited to the outbound section? I tried to apply mocking in the outbound section but then I would need to "skip" the entire <backend> section as there is no backend yet..
This policy below works and I get a nice sample json back, but it's not compressed.
<policies>
<inbound>
<base />
<set-header name="Content-Encoding" exists-action="override">
<value>gzip</value>
</set-header>
<mock-response status-code="200" content-type="application/json" />
</inbound>
<backend />
<outbound />
<on-error>
<base />
</on-error>
</policies>

I actually got it to work using <return-response> instead. So if anyone in the future stumbles upon this, here is the complete policy:
<policies>
<inbound>
<base />
<return-response>
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-header name="Content-Encoding" exists-action="override">
<value>gzip</value>
</set-header>
<set-body>{
"success": true,
"data": {
"foo": [
{
"id": 1,
"bar": "xxx"
},
{
"id": 2,
"bar": "yyy"
},
{
"id": 3,
"bar": "zzz"
}
]
}
}</set-body>
</return-response>
</inbound>
<backend />
<outbound />
<on-error>
<base />
</on-error>
</policies>

Related

Parsing JSON Array in Azure APIM policy

I need some help Parsing JSON Array in Azure APIM policy. My input to my API is a JSON Array but I want the output of the API to be JSON without the "[]", I just can't get the policy to remove them.
Here is the JSON Array input to my API:
[
{
"id": "myId",
"topic": "myTopic",
"subject": "/apis/test;Rev=1",
"data": {
"resourceUri": "myResourceUri"
},
"eventType": "Microsoft.ApiManagement.APIUpdated",
"dataVersion": "1",
"metadataVersion": "1",
"eventTime": "2022-09-08T14:22:46.7708654Z"
}
]
But I would like the Output of the policy to remove the square brackets [], like this:
{
"id": "myId",
"topic": "myTopic",
"subject": "/apis/test;Rev=1",
"data": {
"resourceUri": "myResourceUri"
},
"eventType": "Microsoft.ApiManagement.APIUpdated",
"dataVersion": "1",
"metadataVersion": "1",
"eventTime": "2022-09-08T14:22:46.7708654Z"
}
Here is my policy (which I copied from a tutorial and manipulated):
<policies>
<inbound>
<base />
<set-variable value="#(context.Request.Headers["Aeg-Event-Type"].Contains("SubscriptionValidation"))" name="isEventGridSubscriptionValidation" />
<set-variable value="#(context.Request.Headers["Aeg-Event-Type"].Contains("Notification"))" name="isEventGridNotification" />
<choose>
<when condition="#(context.Variables.GetValueOrDefault<bool>("isEventGridSubscriptionValidation"))">
<return-response>
<set-status code="200" reason="OK" />
<set-body>#{
var events = context.Request.Body.As<string>();
JArray a = JArray.Parse(events);
var eventGridData = a.First["data"];
var validationCode = eventGridData["validationCode"];
var jOutput =
new JObject(
new JProperty("validationResponse", validationCode)
);
return jOutput.ToString();
}</set-body>
</return-response>
</when>
<when condition="#(context.Variables.GetValueOrDefault<bool>("isEventGridNotification"))">
<send-one-way-request mode="new">
<set-url>https://hooks.slack.com/services/mySlackHandle</set-url>
<set-method>POST</set-method>
<set-body>#{
var events = context.Request.Body.As<string>();
JArray a = JArray.Parse(events);
var eventGridData = a.First["data"];
var song = eventGridData["song"];
return new JObject(
new JProperty("text", String.Format(" {1}",
song, a))).ToString();
}</set-body>
</send-one-way-request>
<return-response>
<set-status code="200" reason="OK" />
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
ANY HELP GREATLY APPRECIATED! Extra points if you can remove the reference to "song", which I cannot without breaking the policy...
You have to convert your json array to a json object like this:
<set-body>#(Newtonsoft.Json.JsonConvert.SerializeObject((JObject)(context.Request.Body.As<JArray>(preserveContent: true))[0]))</set-body>
Your can remove the serialization if you want to keep the body as a json object. But the trick is to capture the body as a JArray and then use the [0] to choose the "first" object in the array and thereafter convert your body to a JObject.

output of the json not formatted in APIM developer portal

output of the json not formatted in APIM developer portal and HTTP response gives as follows also
HTTP/1.1 200 OK
api-supported-versions: 1.0,2.0
content-length: 1979
content-type: application/json; charset=utf-8
date: Tue, 06 Sep 2022 11:50:38 GMT
strict-transport-security: max-age=15552001; includeSubDomains; preload
in above it say content-type: application/json but out put as below (in the developer portal responses section content type also "application/json" )
{
"totalRowCount": 1,
"data": [
{
"Code": "",
"prCode": "CW1208",
"Name": "CW1208 Quarterly Milestones",
"description": "",
"CategoryCode": "Efficiency",
"dataSource": "",
"custodian": "",
"TimeframeCode": "Lag",
"TypeName": "Single",
"active": true,
"InputTypeCode": "Input",
"rOfficer": "Stephen MCKAY",
"rOfficerCode": "Stephen ",
"AggregationMethodCode": "Average",
"reportingPeriod": "Quarter(s)",
"responsibleOfficer": "Stephen ",
"unit": "%",
"method": "MOREISBETTER",
"datefrom": "2021-04-01T00:00:00",
"dateto": "2021-06-30T00:00:00",
"target": 100.00,
"actual": 0.00,
"variance": 0.00,
"performance": 0.000000,
"trafficLight": "OFFTRACK",
"comment": "Quarterly comment.."
}
]
}
Any idea how to fix this?
This is how I added the response
in the developer portal example output
all operation policies
<set-header name="Token" exists-action="skip">
<value>#(context.Request.OriginalUrl.Query.GetValueOrDefault("Token"))</value>
</set-header>
<choose>
<!--QA-->
<when condition="#(context.Subscription.PrimaryKey.Equals("8ug4ac4a02"))">
<set-backend-service base-url="https://xxxxx.com/API/api/v1/" />
</when>
<!--Other Clients-->
<otherwise>
<set-backend-service base-url="https://xxxxemo.xxxx.com/api/v1/" />
</otherwise>
</choose>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<set-header name="X-Powered-By" exists-action="delete" />
<set-header name="X-AspNet-Version" exists-action="delete" />
<set-body template="none"></set-body>
<choose>
<when condition="#(context.Response.StatusCode == 404)">
<set-status code="200" reason="No Records Found" />
<set-body template="none">{"totalRowCount":0,"data":[{"":""}]}</set-body>
</when>
</choose>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Please set the response content type to application/json.
Outbound policy:
<outbound>
<set-header name="X-Powered-By" exists-action="delete" />
<set-header name="X-AspNet-Version" exists-action="delete" />
<set-body template="none"></set-body>
<choose>
<when condition="#(context.Response.StatusCode == 404)">
<set-status code="200" reason="No Records Found" />
<!--
<set-body template="none">{"totalRowCount":0,"data":[{"":""}]}</set-body>
-->
<set-body>#{
var body = new JObject();
body["totalRowCount"] = 0;
var data = new JArray();
var dataValue = new JObject();
dataValue[""] = "";
data.Add(dataValue);
body["data"] = data;
return body.ToString();
}</set-body>
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
</when>
</choose>
<base />
</outbound>
Result:

Azure APIM-Not able to access json body values in liquid template

I'm trying to build an API in azure and trying to modify the incoming json request using liquid template via set body policy. But the json elements are coming as null
Incoming json request
{
"GetOrderDetailsResponse": {
"OrderId": 1,
"OrderDate": "2018-08-13",
"OrderLines": {
"OrderLine": [
{
"Product": "Pizza Margherita",
"Amount": 5
},
{
"Product": "Pizza Calzone",
"Amount": 2
},
{
"Product": "Pizza Funghi",
"Amount": 1
}
]
}
}
}
Policy code
<policies>
<inbound>
<base />
<return-response response-variable-name="existing response variable">
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body template="liquid">
{
"orderId" : "{{body.GetOrderDetailsResponse.OrderId}}",
"orderDate" : "{{body.GetOrderDetailsResponse.OrderDate | Date: "dd/MM/yyyy"}}",
"orderLines" : [
{% JSONArrayFor orderline in body.GetOrderDetailsResponse.OrderLines %}
{
"product" : "{{orderline.Product}}",
"amount" : "{{orderline.Amount}}"
}
{% endJSONArrayFor %}
]
}
</set-body>
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<!--Create JSON Response via liquid template-->
</outbound>
<on-error>
<base />
</on-error>
</policies>
Response is blank
{
"orderId": "",
"orderDate": "",
"orderLines": []
}
I'm new to this,please advise if i'm missing something obvious
As mentioned here in the official docs, the Content-Type header must be set to application/json for the body to parsed and available to the liquid template.
In this case, you could either make sure the request sent has it set or manually set it in the inbound scope (not inside return-response) using the set-header policy

How can i get Element Value in Json payload with out Square brackets around element value?

I am using a payload mediator in the workflow to Update my JSON payload. I have successfully updated the payload with incoming request values and return output in JSON only. But in my JSON response payload after payload mediator, I am getting [ Value ] for the JSON element against which I have updated values.
I did not want my JSON element value enclosed within [] braces. I want a simple output like element: "Value".
Below is my JSON Response I receive after using the Payload mediator. Please guide me on how can I achieve the required output.
{
"FIXML": {
"Header": {
"RequestHeader": {
"MessageKey": {
"RequestUUID": [
"FEBA_1553756445880"
],
"ServiceRequestId": "executeFinacleScript",
"ServiceRequestVersion": "10.2",
"ChannelId": "COR"
},
"RequestMessageInfo": {
"BankId": [
"04"
],
"TimeZone": "GMT+05:00",
"EntityId": "",
"EntityType": "",
"ArmCorrelationId": "",
"MessageDateTime": 2020-03-03T16: 59: 10.000
},
"Security": {
"Token": {
"PasswordToken": {
"UserId": "11111",
"Password": ""
}
},
"FICertToken": "",
"RealUserLoginSessionId": "",
"RealUser": "",
"RealUserPwd": "",
"SSOTransferToken": ""
}
}
},
"Body": {
"executeFinacleScriptRequest": {
"ExecuteFinacleScriptInputVO": {
"requestId": [
"validateAcct.scr"
]
},
"executeFinacleScript_CustomData": {
"ACCT_NUM": [
"01122507578"
],
"PHONE_NUM": [
"59887834"
],
"NIC": [
"G2105493001653"
]
}
}
}
}
}
Conversion of Above JSON into XML as below.
<?xml version="1.0" encoding="UTF-8"?>
<FIXML>
<Body>
<executeFinacleScriptRequest>
<ExecuteFinacleScriptInputVO>
<requestId>
<element>validateAcct.scr</element>
</requestId>
</ExecuteFinacleScriptInputVO>
<executeFinacleScript_CustomData>
<ACCT_NUM>
<element>01122507578</element>
</ACCT_NUM>
<NIC>
<element>G2105493001653</element>
</NIC>
<PHONE_NUM>
<element>59887834</element>
</PHONE_NUM>
</executeFinacleScript_CustomData>
</executeFinacleScriptRequest>
</Body>
<Header>
<RequestHeader>
<MessageKey>
<ChannelId>COR</ChannelId>
<RequestUUID>
<element>FEBA_1553756445880</element>
</RequestUUID>
<ServiceRequestId>executeFinacleScript</ServiceRequestId>
<ServiceRequestVersion>10.2</ServiceRequestVersion>
</MessageKey>
<RequestMessageInfo>
<ArmCorrelationId />
<BankId>
<element>04</element>
</BankId>
<EntityId />
<EntityType />
<MessageDateTime>2020-03-03T18:31:48.000</MessageDateTime>
<TimeZone>GMT+05:00</TimeZone>
</RequestMessageInfo>
<Security>
<FICertToken />
<RealUser />
<RealUserLoginSessionId />
<RealUserPwd />
<SSOTransferToken />
<Token>
<PasswordToken>
<Password />
<UserId>11111</UserId>
</PasswordToken>
</Token>
</Security>
</RequestHeader>
</Header>
</FIXML>
Both JSON and XML files are used as Input and Output to Data mapper. But After data when I logged the message I get empty XML as below.
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<FIXML>
<Body>
<executeFinacleScriptRequest>
<ExecuteFinacleScriptInputVO>
<requestId>
<element />
</requestId>
</ExecuteFinacleScriptInputVO>
<executeFinacleScript_CustomData>
<ACCT_NUM>
<element />
</ACCT_NUM>
<NIC>
<element />
</NIC>
<PHONE_NUM>
<element />
</PHONE_NUM>
</executeFinacleScript_CustomData>
</executeFinacleScriptRequest>
</Body>
<Header>
<RequestHeader>
<MessageKey>
<ChannelId />
<RequestUUID>
<element />
</RequestUUID>
<ServiceRequestId />
<ServiceRequestVersion />
</MessageKey>
<RequestMessageInfo>
<ArmCorrelationId />
<BankId>
<element />
</BankId>
<EntityId />
<EntityType />
<MessageDateTime />
<TimeZone />
</RequestMessageInfo>
<Security>
<FICertToken />
<RealUser />
<RealUserLoginSessionId />
<RealUserPwd />
<SSOTransferToken />
<Token>
<PasswordToken>
<Password />
<UserId />
</PasswordToken>
</Token>
</Security>
</RequestHeader>
</Header>
</FIXML>
</soapenv:Body>
</soapenv:Envelope>
Please Guide me here. How this conversion is properly done.

How do you accumulate values within a ForEach loop in Mule?

I have the below json output:
{
"results": [
{
"ID": "1",
"ImageID": "2",
"Name": "Test1",
"Owner": "sysadmin",
"Author": "sysadmin",
"Creator": "sysadmin"
},
{
"ID": "2",
"ImageID": "23",
"Name": "Test2",
"Owner": "sysadmin",
"Author": "sysadmin",
"Creator": "sysadmin"
}
]
}
For each ID in above response, i need to invoke the rest service passing ID as a parameter and the rest service will send me a response back. I have to consolidate all the output into a single json response in mule.
I have tried using for each and enricher but could not able to build it. Below is the code which i am using.
<foreach doc:name="For Each Loop">
<logger level="INFO" message="#[payload]" doc:name="Logger" category="INFO"/>
<json:json-to-object-transformer doc:name="JSON to Object"/>
<enricher doc:name="Message Enricher">
<http:request config-ref="SAM" path="/abc/#[payload.ID]" method="GET" doc:name="HTTP"/>
<enrich target="#[flowVars.ID]" source="#[payload[0].ID]"/>
</enricher>
<logger level="INFO" message="#[flowVars.ID]" doc:name="Logger" />
<expression-component doc:name="Expression"><![CDATA[payload.ID = flowVars.ID; ]]></expression-component>
</foreach>
Kindly help me with the way to fix this !!
Thanks
You need to initialize an empty array before the for-each loop and add to that array within the for-each:
<set-variable variableName="idList" value="#[[]]" doc:name="Variable - Init idList"/>
<foreach doc:name="For Each Loop">
<logger level="INFO" message="#[payload]" doc:name="Logger" category="INFO"/>
<json:json-to-object-transformer doc:name="JSON to Object"/>
<enricher doc:name="Message Enricher">
<http:request config-ref="SAM" path="/abc/#[payload.ID]" method="GET" doc:name="HTTP"/>
<enrich target="#[flowVars.ID]" source="#[payload[0].ID]"/>
</enricher>
<logger level="INFO" message="#[flowVars.ID]" doc:name="Logger" />
<expression-component doc:name="Expression"><![CDATA[flowVars.idList.add(flowVars.ID);]]></expression-component>
</foreach>
I cover this topic in this video.
Thanks Jerney !!
I made it working by doing the following:
<set-variable variableName="outputList" value="#[new java.util.ArrayList()]" doc:name="SetEmptyArray"/>
<foreach collection="json:packshots" doc:name="ForEachDocument">
<set-variable variableName="docName" value="#[json:Name]" doc:name="docName"/>
<http:request config-ref="AH_DAM_API_Configuration" path="${ah.dam.api.get.renditions.path}#[json:Name]" method="GET" doc:name="InvokeAHDamService"/>
<set-payload value="#[xpath3('//*:service/*:document',payload,'NODE')]" doc:name="fetchRenditionInfo"/>
<expression-transformer expression="#[flowVars.outputList.add(payload)]" doc:name="AppendResponseToArray"/>
</foreach>
I have used from the savedOutput for array variable.