MarshalError: Unable to marshal response: JSONDecodeError AWS Lambda - javascript

I have written a lambda function in AWS which fetches the data from Dynamo DB and return in JSON format. It take a request input body in a format - {"Datestamp":"2021-01-11"} and return reports for this date.
I am calling this from a web page using java script but I am getting ``unable to marshal response``` error.
Javascript Code -
$.ajax({
type : "POST",
contentType : "application/json",
url : "https://mypoc-app.com/api/",
data:
{
"Datestamp" : "2021-02-15"
},
headers: {
'Authorization': 'Basic',
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': 'DELETE, POST, GET, OPTIONS',
'Access-Control-Allow-Credentials' : true
//'Access-Control-Allow-Headers': 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With',
},
dataType : "json",
success : function(data,status) {
console.log("Date format is " + data);
if (response != null)
{
drawTable(response.data);
}
},
error: function () {
console.log("Error");
}
});
Lambda function -
def lambda_handler(event, context):
try:
result = []
queryresponse = resultstable.scan()
for i in queryresponse['Items']:
result.append(i['reports'])
block=['{"type": "section","text": {"type": "mrkdwn","text": "*Found below reports using Datestamp provided*"}}']
for item in result:
print(event["body"])
body = json.loads(event["body"])
if item.find(body['Datestamp']) != -1:
itema='{"type": "section","text": {"type": "mrkdwn","text": "<https://%s/%s/%s/index.html|%s>"}}' % (URL,Prefix,item,item)
block.append(itema)
block=('[{}]'.format(', '.join(block)))
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': block,
"isBase64Encoded": False
}
except Exception as e:
print(e)
return(e)
Error Logs in Cloudwatch -
START RequestId: XXXXXXXXXXXXXXXXXXXX Version: $LATEST
Datestamp=2021-02-15
Expecting value: line 1 column 1 (char 0)
[ERROR] Runtime.MarshalError: Unable to marshal response: JSONDecodeError('Expecting value: line 1 column 1 (char 0)') is not JSON serializable
END XXXXXXXXXXXXXXXXXXXX
I believe it has something to do with the way I am passing date in the request or the way lambda is handling it because certainly from the cloud watch logs it doesn't look like it's in a JSON format.
Can someone please provide their expertise in this case as I have already scratched my head around it?

As you said it works fine from the console - i suspect your issue is trying to invoke it using AJAX. The better way would be to use the AWS SDK for JavaScript. Use the Lambda Client API to invoke the Lambda function from within a Script tag.
Here is the examples for JS API for Lambda:
https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/javascriptv3/example_code/lambda
To invoke a Lambda function, you can call the invoke operation. See this Java example. Port this example to JS API.
https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javav2/example_code/lambda/src/main/java/com/example/lambda/LambdaInvoke.java
To pass data, use the InvokeRequest object.

Related

Request in javascript (from python)

I have attempted to create a request in javascript, that has previously worked using python just fine.
the following is an accurate representation of the code I used to post the request with python:
url = 'https://website.com/api/e1'
header = {
'authorization': 'abcd1234'
}
payload = {
'content': "text",
}
r = requests.post(url, data=payload,headers=header )
This (above) works just fine in python.
now what I did in javascript is the following:
payload = {
"content": "this is text",
};
fetch("https://website.com/api/e1", {
method: "POST",
headers: {
"authorization":
"abcd1234",
},
body: JSON.stringify(payload),
});
but this is returning the error
400- Bad request
When using data parameters on python requests.post, the default Content-Type is application/x-www-form-urlencoded(I couldn't find it on the document, but I checked the request. If you know, please leave a comment).
To achieve the same result with fetch, you must do as follows.
const payload = {
'content': 'this is text',
};
fetch('https://website.com/api/e1', {
method: 'POST',
headers: {
'authorization': 'abcd1234',
},
body: new URLSearchParams(payload),
});
You don't need to do this body: JSON.stringify(payload), rather you can simply pass payload in body like this body:payload

Nodejs request post with body include api key

I have been trying about a week but I couldn't make a post request to get a result.
I tried a bunch of middlewares (exp: 'request', 'axios', 'reqclient','superagent etc..) but I couldn't make it.
Please provide me a simple post request with sending API key and body.
I also read all the documentation.
Please check below to see what I want :
*Authentication API key required.
*O-Auth Scopes trades
*Input One of: user_id + token or user_url is required.
here is my one of try :
const request = require('request-promise')
const options = {
method: 'POST',
uri: 'api-site.com/Offer/v1/',
headers: {
'User-Agent': 'Request-Promise',
'Authorization': 'Basic 123123asdasd123123'
},
body: {
user_url: "site.com/user/user1234123",
otherparams: "parameter"
},
json: true
};
request(options)
.then(function (response) {
Console.log(response);
})
.catch(function (err) {
console.log('Error ', err.message);
});
I am getting this output :
Error : 401 - {"status":401,"time":1540458426,"message":"API Key Required"}
I tried some other request post middle-wares and played with content-type (application/json. dataForm, x-www-form-urlencoded) or
changed the location of my API key from header to body or
tried my API key inside of auth{authorization: "API Key"}
tried much more.
the result didn't change. I got the same output or errors.
EDIT :
this is the link that I am trying to do but got stack :
check here
Solved !
Everything works great. Problem was I needed to send my API Key base64 string.
Buffer.from("your_api_key_value" + ":", "ascii").toString("base64")

Bad request while trying to access Github's v4 API with graphql.js

I am trying to retrieve some data from Github's GraphQL API using graphql.js library.
var graph = graphql("https://api.github.com/graphql", {
method: "POST",
headers: {
"Authorization": "Bearer <my-token-here>",
"Content-Type": "application/json"
},
fragments: {
rateLimitInfo: "on RateLimit {cost,remaining,resetAt}"
}
});
graph(`
query repo($name: String!, $owner: String!){
repository(name:$name, owner:$owner){
id
}
}
`,{
name: "freeCodeCamp",
owner: "freeCodeCamp"
}).then(function(response){
console.log(response);
}).catch(function(error){
console.log(error);
});
My promise is not being fulfilled and always failing. I am getting an HTTP response with code 400 (Bad Request) and the error argument of the catch function reads:
{
message: "Problems parsing JSON",
documentation_url: "https://developer.github.com/v3"
}
I have already tried passing the variables as JSON, like so:
{
"name": "freeCodeCamp",
"owner": "freeCodeCamp"
}
But it didn't help. I got the same bad request.
Looking at the Network tab of Chrome's inspector I see what the request payload is. Adding it here in case it give any clues or help.
query=query%20repo(%24name%3A%20String!%2C%20%24owner%3A%20String!)%7Brepository(name%3A%24name%2C%20owner%3A%24owner)%7Bid%7D%7D&variables=%7B%22name%22%3A%22freeCodeCamp%22%2C%22owner%22%3A%22freeCodeCamp%22%7D
What am I doing wrong?
The default behaviour of graphql.js is to send the body in form-url-encoded format whereas Github GraphQL api accepts only JSON format. From graphql.js readme :
As default, GraphQL.js makes a POST request. But you can change the
behavior by setting asJSON.
var graph = graphql("http://localhost:3000/graphql", {
asJSON: true
});
You can see the difference here
The following will work as expected :
var graph = graphql("https://api.github.com/graphql", {
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
asJSON: true
});
graph(`
query repo($name: String!, $owner: String!){
repository(name:$name, owner:$owner){
id
}
}
`, {
name: "freeCodeCamp",
owner: "freeCodeCamp"
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
});

HTTPS request not posting body of REST request

I'm trying to POST to an API endpoint on my server. I know my endpoint works because if I use Advanced REST Client, I can hit it and get a JSON response as expected. The problem seems to be that no data is being sent in the body of my request despite calling request.write(postData) which contains a key, value pair. Without this data being sent in the body, my server returns a 401 error as expected without this information. Printing out the content of the POST server-side is empty but I'm clueless as to why it's empty.
var postData = querystring.stringify({
"access_token" : accessToken,
"id": applianceId
});
var serverError = function (e) {
log("Error", e.message);
context.fail(generateControlError(requestName, "DEPENDENT_SERVICE_UNAVAILABLE", "Unable to connect to server"));
};
var callback = function(response) {
var str = "";
response.on("data", function(chunk) {
str += chunk.toString("utf-8");
});
response.on("end", function() {
result = generateResult(CONTROL, requestName.replace("Request", "Confirmation"), messageId);
context.succeed(result);
});
response.on("error", serverError);
};
var options = {
hostname: REMOTE_CLOUD_HOSTNAME,
port: 443,
path: REMOTE_CLOUD_BASE_PATH + "/" + endpoint,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
};
var request = https.request(options, callback);
request.on("error", serverError);
//This doesn't seem to write anything since if I print out the POST
//data server-side it's empty; however, if I print out the value of
//postData here, it looks as expected: 'access_token=xxxxx'
request.write(postData);
request.end();
I have testing you code again httpbin.org/post and it seems that it is working.
I believe that the issue related to, that your should POST application/json and not "application/x-www-form-urlencoded
Please try to change the header
headers: {
"Content-Type": "application/json"
}
Then, try to change the postData to JSON string:
var postData=JSON.stringify({access_token:"xxxxx"})
To be sure that problem you success to send and the problem is not local (maybe there is an issue in your server), change the target to mirror URL:
var options = {
hostname: "httpbin.org",
path:'/post',
port: 443,
method: "POST",
headers: {
"Content-Type": "application/json"
}
};
If there is no problem in your NodeJS version, the is the response you should get: (It is mean that the server got the posted data)
{
"args": {},
"data": "{\"access_token\":\"xxxxx\"}",
"files": {},
"form": {},
"headers": {
"Content-Length": "24",
"Content-Type": "application/json",
"Host": "httpbin.org"
},
"json": {
"access_token": "xxxxx"
},
"origin": "5.29.63.30",
"url": "https://httpbin.org/post"
}
BTW: I really recommend you to move to a library to manage the request for you:
https://github.com/request/request - Very popular
https://github.com/request/request-promise - For popular who like to use the Promise syntax (The next thing in JavaScript)
https://github.com/visionmedia/superagent - For people who like to write same code in Browser & Server

jQuery.ajax to $http

I used this function
jQuery.ajax({
type: 'POST',
url: urlSubmit,
timeout: 5000,
dataType: 'text',
data: {
date : dataDate,
url : dataUrl,
domaine : dataDomaine,
email : dataEmail,
destinataire : dataDestinataire,
msg : dataMsg
},
"success": function (jqXHR, textStatus, errorThrown) {
console.log("AJAX success :) - statut " + textStatus);
$timeout(successMailZR_alerte, 3000);
},
"error": function (jqXHR, textStatus, errorThrown) {
console.log("AJAX fail :/ - statut " + textStatus);
$timeout(errorMailZR_alerte, 3000);
}
});
Whats the code is doing : code POST to a php script who send an email.
but, since i rewrited my code in a complete angularjs app, i do it like this :
$http({
method: 'POST',
url: urlSubmit,
timeout: 5000,
cache: false,
data: {
date : dataDate,
url : dataUrl,
domaine : dataDomaine,
email : dataEmail,
destinataire : dataDestinataire,
msg : dataMsg
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
responseType: 'text',
}).
success(function(data, status, headers, config) {
console.log("AJAX success :) - statut " + status);
$timeout(successMailZR_alerte, 3000);
}).
error(function(data, status, headers, config) {
console.log("AJAX fail :/ - statut " + status);
$timeout(errorMailZR_alerte, 3000);
});
Problem is : with $http, i have a success 200 but nothing is posted and i have no return in my email. What's the problem ?
The problem is that jQuery's POST does send your data as form data (e.g. key-value pairs) (https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Sending_and_retrieving_form_data) whereas AngularJS sends your data in the request payload. For a difference between the two see the following SO question: What's the difference between "Request Payload" vs "Form Data" as seen in Chrome dev tools Network tab
In order to make your angular script works with your server you have to convert your data to a URL encoded string as described here: How can I post data as form data instead of a request payload?. Simply setting headers: {'Content-Type': 'application/x-www-form-urlencoded'} is not enough.
A different approach would be to adapt the back-end of your application to parse the message payload instead of the form data parameters.
To understand this one need to understand the request headers set by angular and jquery, There are differences with the headers like when request is post by jQuery then header might look like this:
POST /some-path HTTP/1.1
Content-Type: application/x-www-form-urlencoded // default header set by jQuery
foo=bar&name=John
You can see this in form data in the request made in the browser, if you use chrome then you can see this in chrome inspector at network tab, if you click the request then you can see the form data and content headers set by the jQuery.
On the other side with angular js $http service, when a request is made then you can find these:
POST /some-path HTTP/1.1
Content-Type: application/json // default header set by angular
{ "foo" : "bar", "name" : "John" }
The real difference is this you have a request payload not usual form data which is used by jQuery. so you need to do something extra at the server side like below.
Use this:
$data = json_decode(file_get_contents("php://input"));
echo $data->date;
// and all other params you have sent
This is due to its default headers
Accept: application/json, text/plain, * / *
Content-Type: application/json
and jQuery unlikely have something else:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

Categories