I am trying to properly setup Body Mapping and Header Mapping in the Integration Response for an API Gateway endpoint.
In our Lambda we have
if (response.statusCode == 200) {
context.succeed(output);
} else if (response.statusCode == 206) {
var paginationObject = {
errorType : "PartialContent",
errorCode : 206,
detailedMessage : "PartialContent Returned",
stackTrace : [],
data : {
output
}
};
context.fail(JSON.stringify(paginationObject));
}
I then handle fetching this in the Integration Response using a Lambda Error Regex of .*PartialContent.* and have my Body Mapping Template as
#set($allParams = $input.params())
#set($body = $util.parseJson($input.json('$.errorMessage')))
$body
This gives me the correct HTTP status code and JSON output, but it has too much data in the body. The response looks like:
{
"errorType":"PartialContent",
"errorCode":206,
"detailedMessage":"PartialContent Returned",
"stackTrace":[],
"data":{
"output":{
"status":206,
"bodyJson":[{"call_date":"2017-08-19 18:17:21"}],
"headers":{"date":"Thu, 02 Nov 2017 18:36:52 GMT",
"server":"Apache",
"x-pagination-page-size":10}
}
}
}
I want the headers to actually appear as headers in the response, and I want the body to just be the content inside of bodyJson
I've tried to change the body mapping template to use $body.data.output.bodyJson, but when I do that the body is completely empty. I've also got the headers set in the Header Mappers, trying both integration.response.body.headers.x-pagination-page-size and integration.response.header.x-pagination-page-size but both times the header is blank, even though I can see the proper values in the JSON output.
How do I get just the bodyJson element to be output as the body of the response? And how do I properly get the headers mapped?
Did you try to use Lambda Error Regex in Integration Response?
For example:
.*"status":400.*
body mapping templetes:
#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))
{
"status" : "$errorMessageObj.status",
"errorType" : "$errorMessageObj.errorType",
"message" : "$errorMessageObj.errorMessage"
}
I created an error function in my Lamda:
function error(status, errorType, errorMessage, callback){
callback(JSON.stringify({
status: status,
errorType: errorType,
errorMessage: errorMessage
}));
}
usage:
error(404, "Not Found", "Resource is not found", callback);
Related
i am currently building an frontend app to display a generated qr code from an api. I started to implement the code but got a problem with the parsing of the response
here is the frontend code with the call
<template>
<div>
<p>test</p>
</div>
</template>
<script>
// Configuration
let myConfiguration = {
"Account" : "CH4431999123000889012",
"CreditorName" : "Muster AG",
"CreditorAddress1" : "Hauptstrasse 1",
"CreditorAddress2" : "8000 Zürich",
"CreditorCountryCode" : "CH",
"DebtorName" : "LivingTech GmbH",
"DebtorAddress1" : "Dörflistrasse 10",
"DebtorAddress2" : "8057 Zürich",
"DebtorCountryCode" : "CH",
"Amount" : "1.50",
"ReferenceNr" : "21000000000313947143000901",
"UnstructuredMessage" : "Mitteilung zur Rechnung",
"Currency" : "CHF",
"QrOnly" : "false",
"Format" : "PDF",
"Language" : "DE"
}
// Call function to create invoice
let myFile = generateQrInvoice(myConfiguration);
// Work with binary data
if(myFile != null) {
// ...
}
function generateQrInvoice(myRequestConfiguration) {
// Main configuration
let myEndpointUrl = "http://qrbillservice.livingtech.ch";
let myEndpointPath = "/api/qrinvoice/create/";
let myApiKey = "(falseApiKey)";
// GET parameters
let myGetParams = new URLSearchParams(myRequestConfiguration);
// Perform request
fetch(myEndpointUrl + myEndpointPath + "?" + myGetParams, {
method: "GET",
mode: "cors",
cache: "no-cache",
headers: {
"APIKEY": myApiKey,
"Accept": "application/json"
}
}).then(function (myResponse) {
try {
// Check status
if(myResponse.status == 200) {
// Read and parse JSON
let myJsonObject = JSON.parse(myResponse);
// Check if error
if(myJsonObject["isSuccessed"] == "true") {
if("base64Content" in myJsonObject && myJsonObject["base64Content"].trim() != "") {
// E.g. send file to client
let myBlob = new Blob(atob(myJsonObject["base64Content"]), {type: "application/pdf"});
let myBlobUrl = URL.createObjectURL(myBlob);
window.open(myBlobUrl);
// Return data
return atob(myJsonObject["base64Content"]);
} else {
throw "no data provided";
}
} else {
throw myJsonObject["message"];
}
} else {
throw "status code " . myResponse.status;
}
}
catch(e) {
// Handle exception
console.warn("Error: " + e.message, e);
return null;
}
}).catch(function (err) {
// Handle exception
console.warn("Error: " + err.message, err);
return null;
});
}
</script>
and here is the response i get when i inspect on the browser :
Error: Unexpected token 'o', "[object Response]" is not valid JSON SyntaxError: Unexpected token 'o', "[object Response]" is not valid JSON
at JSON.parse (<anonymous>)
at app.vue:61:42
I didn't write the apikey here but it is written on my code.
As it has been a long time since i didn't code like this, i don't really see yet how to tackle the problem. I tried to test with postman but it appears my request is not good yet.
If someone has an idea, i would be very happy to learn.
Thank you very much in advance,
Eugene
So i test myResponse and it is a JSON.
However the problem remains : i saw in the console that the api answers successfully api response
So i figured that i could just replace
let myJsonObject = JSON.parse(myResponse)
by
let myJsonObject = myResponse
and try to see what goes.
Now it goes directly in the catch(e) and send me an error response.
It looks like in my code, i don't go in the right direction to use the information i got from the api.
Here is partially the information i got : {"isSuccessed":true,"statusCode":200,"mimeType":"application/pdf","message":"QrBill is successfully generated","isQrOnly":false,"errors":"null","base64Content":(here is the content, i didn't added because it is quite long)}
my question therefore is how could recover the pdf and show it to the end user?
I have a Logic App that gets the contents from a SharePoint (.xlsx) and posts the body to an endpoint to get processed. now the content I see is a base64-encoded file, what I wanted to do was to post this data as is.
when I try to post it using postman it gets accepted successfully but when it is posted form the Logic app I get
BadRequest. Http request failed: the content was not a valid JSON.
but I can see that the body that was meant to be sent is of the type, which is a valid Json
{
"$content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"$content": "AA....VeryLong...B1241BACDFA=="
}
also tried this expression
decodeBase64(triggerBody()?[body('getFile')])
but I get a different error
InvalidTemplate. Unable to process template language expressions in action 'HTTP' inputs at line '1' and column '2565': 'The template language expression 'decodeBase64(triggerBody()?[body('getFile')])' cannot be evaluated because property '{
"$content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"$content": "UEsDBBQABgAIAAAAIQDuooLHjAEAAJkGAAATAAgCW0Nvb...
What I want to achieve is simple really I want to post to my end point the Json as is or the contents of the base64Encoded string.
If you decode the content with base64 you will find the content is garbled. This is because the content is in ooxml format then encoded with base64. And in logic app you could not decode the ooxml.
First solution, you could use Azure Function to write a method to read the document then return the content. Then in logic app call the function to get the content.
Second solution, change your file to a directly readable file(like .txt file), this way I tried and you could parse it Json.
Can you send me your postman request save it in collect and then export as file.
I think what you can do in postman can be done in logic app too.
Or send me your code I can modify it.Make sure you have post as body and it matches the parameter of Post at web api level.
var Webrequestdata = {
"webserviceurl": "http://examplecom/u/b/b/e.ee.msg",
"username": "123"
};
$.ajax({
cache: false,
type: "POST",
url: 'http://example.com/res/api/Outlookapi',
data: JSON.stringify(Webrequestdata),
contentType: "application/json",
success: function (result) {
console.log("email sent successfully");
},
error: function (response) { alert('Error: ' + response.responseText); }
});
after looking at your statement:
Logic App gets the contents from a SharePoint (.xlsx) and posts the
body to an endpoint to get processed. now the content I see is a
base64-encoded file
i assume your endpoint is still looking for a content type -
vnd.openxmlformats-officedocument.spreadsheetml.sheet
but you are passing a Base64 String
1) check if your "content-type" header is correctly placed change it to application/json if possible
2) Make sure you are processing the base64 string correctly.
In my case, I extracted the base64 string from an image file using Javascript. I got special keys at the start of base64 string like ''data:image/png;base64','ACTUAL BASE 64 STRING...' so i removed the special keys before the actual base64 string with some regular expression.
This sample Json request might help in attaching the base64 Content
Make sure you are converting your request to JSON using JSON.stringify
//var finalString = srcData.replace('data:image/png;base64,','');
var finalString = srcData.replace(/^,+?(\,)/, '');
finalString = srcData.substring(srcData.indexOf(',')+1, srcData.length);
var data = JSON.stringify({
"requests": [
{
"image": {
"content": finalString
},
"features":
[
{
"type": "DOCUMENT_TEXT_DETECTION",
"maxResults": 1
}
]
}
]
});
This is the XMLHttpRequest i used:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
var obj = JSON.parse(this.responseText);
try
{
//do something
}catch(err)
{
//do something
}
}
});
try {
xhr.open("POST", "https://vision.googleapis.com/v1/images:annotate?key=blablabla");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("cache-control", "no-cache");
xhr.setRequestHeader("Postman-Token", "111111111");
xhr.send(data);
}
catch(err) {
//do something
}
I am using node.js (and discord.js) to make a discord bot.
I am using a GET request with the npm request module. Code works as expected when user types "!cat" it gets data from https://aws.random.cat/meow and posts a cat picture HOWEVER sometimes the server will give a 403 forbidden error which results in a HTML page instead of JSON and crashes the bot due to an unexpected token.
I am looking for a way to detect the HTML page and stop the code/post an error message either by detecting the endpoint is HTML instead of JSON, or the contents of the data sent back which would be:
JSON = { file: 'https://catlink.jpg' }
HTML 403 = <!DOCTYPE HTML PUBLIC...
IMG1: Error - HTML page response,
IMG2: Expected responses 1 per request
My current code block is as follows:
//RANDOM CATS
if(command === "cat" || command === "meow"){
//Connection options
var catoptions = {
url: "https://aws.random.cat/meow",
headers: {
'Content-Type': 'application/json',
'Accept': 'application.json'
}
};`
//Send the request
let request = require("request");
request(catoptions, function(err, response, body){
if(err){
console.log("error code #002");
} else {
//Receive the body of the JSON
var catresult = JSON.stringify(body); //stringify incase page returns HTML 403 error - Will recieve "<!DOCTYPE HTML PUBLIC..." as first bit of data
console.log(catresult) //Send to log to see if JSON "cat pic" data is returned or the HTML 403 error
let meowdata = JSON.parse(body);
//Responbse body
let meowpic = meowdata.file;
console.log(meowpic); //Send link to console
message.channel.send(meowpic); //Send link to discord channel with discord.js
}
});
} //END OF RANDOM CATS
JSON.parse throws if an invalid JSON is passed, and HTML is not valid JSON, you have to catch the exception to avoid a crash.
From the docs:
Throws a SyntaxError exception if the string to parse is not valid
JSON.
request(catoptions, function(err, response, body) {
if (err) {
console.log("error code #002");
} else {
try {
//Receive the body of the JSON
let catresult = JSON.stringify(body); //stringify incase page returns HTML 403 error - Will recieve "<!DOCTYPE HTML PUBLIC..." as first bit of data
console.log(catresult) //Send to log to see if JSON "cat pic" data is returned or the HTML 403 error
let meowdata = JSON.parse(body);
//Responbse body
let meowpic = meowdata.file;
console.log(meowpic); //Send link to console
message.channel.send(meowpic); //Send link to discord channel with discord.js
} catch (e) {
console.error(e);
}
}
});
With Azure Functions, what do you need to do to return a JSON object in the body from a function written in node.js? I can easily return a string, but when I try to return a json object as shown below I appear to have nothing returned.
context.res = {
body: jsonData,
contentType: 'application/json'
};
Based on my recent testing (March 2017). You have to explicitly add content type to response headers to get json back otherwise data shows-up as XML in browser.
"Content-Type":"application/json"
res = {
status: 200, /* Defaults to 200 */
body: {message: "Hello " + (req.query.name || req.body.name)},
headers: {
'Content-Type': 'application/json'
}
};
Full Sample below:
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.log(context);
if (req.query.name || (req.body && req.body.name)) {
res = {
// status: 200, /* Defaults to 200 */
body: {message: "Hello " + (req.query.name || req.body.name)},
headers: {
'Content-Type': 'application/json'
}
};
}
else {
res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
context.done(null, res);
};
If your data is a JS object, then this should just work, e.g.
module.exports = function(context, req) {
context.res = {
body: { name: "Azure Functions" }
};
context.done();
};
This will return an application/json response.
If instead you have your data in a json string, you can have:
module.exports = function(context, req) {
context.res = {
body: '{ "name": "Azure Functions" }'
};
context.done();
};
Which will return an application/json response because it sniffs that it is valid json.
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
context.res = {
// status: 200, /* Defaults to 200 */
body: {"data":"Hello"},
headers: {
'Content-Type': 'application/json'
}
};
}
else {
// res = {
// status: 400,
// body: "Please pass a name on the query string or in the request body"
// };
}
context.done(null,res);
I would like to add one more point. Apart from making the body: a JSON object, the request should also contain proper headers telling server what content type we are interested in. I could see that same Azure function when just invoked via browser using URL gives XML response, but when invoking from script or tools like Postman it gives JSON.
I feel like the answer has been given but it hasn't been clearly presented so I thought I'd answer as well in case it will help anyone coming behind me. I too have created a function that most definitely returns a Javascript object but if I copy and paste the URL in the Azure Function UI and just open a new tab in Chrome and try to view the output, I actually get back an XML document that tells me there's an error (not surprising there's an error as many characters in the Javascript would have blown up the XML). So, as others have mentioned, the key is sending the appropriate headers with your request. When you copy/paste the URL into your browser, the browser is sending a request header that looks similar to this:
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
When that happens, you see the XML return as described in this link:
https://github.com/strongloop/strong-remoting/issues/118
In order to get around this problem and see what the data would look like with a JSON request, either use a utility like Postman:
https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en
Accept: application/json
Or use a CURL command and pass in the proper Accept header.
As you can see in the screenshot above, when I provided the proper header, I get back the JSON response I would expect.
You can also use JSON.stringify() to make a valid json string out of your js-object:
jsonData = { value: "test" }:
context.res = {
body: JSON.stringify(jsonData)
};
i have a webservice that is returning this response :
<string xmlns="http://tempuri.org/">{ "H...[ { "ID":"1","Name":"Test"} ]}</string>
when i try to get the response back, i keep getting the error :
"missing ; before statement"
i am just starting to get into this so am probably doing something very wrong.
why is the response not working for me?
my dojo code looks like this
var targetNode = document.getElementById("foo");
var def = dojo.io.script.get({
url: "http://localhost/WebData/PublicData.asmx/HelloWorld",
timeout: 30000,
handleAs: "json",
preventCache: true,
handle: function(error, ioargs) {
var message = "";
switch (ioargs.xhr.status) {
case 200:
message = "Good request.";
break;
case 404:
message = "The requested page was not found";
break;
case 500:
message = "The server reported an error.";
break;
case 407:
message = "You need to authenticate with a proxy.";
break;
default:
message = "Unknown error.";
}
targetNode.innerHTML = message;
}
});
thanks!
david
The get function is trying to parse the response as pure json, as the handleAs attribute is set to 'json'; but the response actually is an xml document containing some json text, causing the error you have.
Either change the response to pure json, like this:
{ "H": [ { "ID":"1","Name":"Test"} ]}
or set the handleAs attribute to 'xml' and parse the response to extract the json content; you can then unmarshall the json string using dojo.fromJson.