JS Promises POST request throws invalid json response body - javascript

I have written a POST client side JS method that when I run (the server side is up and running) I get the following error message:
error { FetchError: invalid json response body at http://localhost:3000/addMovie reason: Unexpected token < in JSON at position 0
at /home/workspace/node_modules/node-fetch/lib/index.js:272:32
at processTicksAndRejections (internal/process/task_queues.js:86:5)
message:
'invalid json response body at http://localhost:3000/addMovie reason: Unexpected token < in JSON at position 0',
type: 'invalid-json' }
The contents of the client file are below. This is part of my attempt to learn JS Promises. It would be really helpful if you could please point me towards the right direction. To run this file, I just do node getPost.js
require('es6-promise').polyfill();
require('isomorphic-fetch');
// TODO
const postData = async ( url = '', data = {})=>{
// console.log(data)
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
const newData = await response.json();
console.log(newData);
return newData
}catch(error) {
console.log("error", error);
// appropriately handle the error
}
}
postData('http://localhost:3000/addMovie', '{"movie": "the matrix", "score": "5"}')
This is my /addMovie route definition.
const data = []
app.post('/addMovie', addMovie )
function addMovie (req, res){
console.log(req.body)
// data.push(req.body)
res.send('POST received')
}

Related

Fetch POST method gives empty body on Express server

I make a POST request from my browser client:
const post = async (url, body) => {
try {
const response = await fetch(url, {
method: `POST`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body
});
return response.json();
} catch (error) {
console.log(error.stack);
}
}
const data = await post(`http://localhost:4050/analyze`, { text });
And I handle it on Express server with this setup:
app.use(express.urlencoded({ extended: true }));
This is my route:
router.post(`/`, errorHandler(async (req, res, next) => {
const { text } = req.body;
console.log(req.body)
const value = await analyze(text);
res.json({ rephrased });
}));
The console.log shows me this:
{ 'object Object': '' }
Why fetch method gives me Object instead of text property?
UPDATE:
When I do Stringify:
method: `POST`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify(body)
The body became like this and console.log shows:
{ '{"text":"asdfasdf"}': '' }
You are passing fetch a plain object for the body and it doesn't know what to do with it, so it calls .toString() and gives you nothing useful.
Pass it a URLSearchParams object instead. (Here I assume text is a string)
const body = new URLSearchParams();
body.append("text", text);
This will convert to a application/x-www-form-urlencoded string.
(You can also omit the headers as fetch can infer the correct Content-Type from the URLSearchParams object.)
Re edit: JSON.stringify will encode the data as JSON. JSON is not application/x-www-form-urlencoded.

Post Request rejected with "Missing body content" error during Fetch

I am sending a Post request, with JavaScript Fetch method. The post attempts to create a Microsoft Teams chat message, via the Microsoft Graph Teams API. However, the server rejects the post request, with the message "missing body content". The payload shows the message body is being sent (Please see screenshot). It appears that the server is rejecting my Post request because it can not parse the body, which is in json format. Can anyone advise how I fix this Fetch issue? I've attached a code snippet for your review.
const data = {content: 'Hello Word'};
const options = {
method: 'POST',
headers: {
Authorization: 'Bearer '+response.accessToken,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
};
fetch(endpoint, options)
.then((response)=>{
const data = response.json();
console.log("RESPONSE1:", data);
return data;
})
.then((data)=>{
console.log("RESPONSE2:", data);
callback(data, endpoint);
})
.catch((error) => console.log("PUSHMSGRAPH-Error:", error));
Try using the API and post it from the reference page with this API
POST /teams/{team-id}/channels/{channel-id}/messages
const teamId = '5834e4c1-2897-4cc3-b21900b56';
const threadid = '19:1df3a1d...#thread.tacv2';
const options = {
authProvider,
};
const client = Client.init(options);
const chatMessage = {
body: {
content: 'Hello World'
}
};
await client.api('/teams/' + teamId + '/channels/' + threadid + '/messages')
.post(chatMessage);

My POST request is failing with a 'Request with GET/HEAD method cannot have body' error

I am trying to use Zoho Creator's ADD RECORDS DATA API (https://www.zoho.com/creator/help/api/v2/add-records.html)
And here's the URL to help you understand my issue. The URL below will show you a JSON of all the variables involved before I run the POST method.
https://vp-expo-node-server.herokuapp.com/eticket/
This above link will show you the result of this controller
exports.addOneExhibitorToCreator = async function(req, res, next) {
try {
const token = await getAccessToken();
const url = process.env.ZOHO_CREATOR_FORM_URL + "/Add_Organisation";
// const organisation = req.body;
const organisation = {
data: {
isActive: true,
Organisation_Name: "Test With Alim",
Type: "Exhibitor",
Short_Name: "test",
Email: "test#fourplusmedia.com",
},
};
const options = {
Method: "POST",
Headers: {
"Content-Type": "application/json",
Authorization: "Zoho-oauthtoken " + token,
},
body: JSON.stringify(organisation),
};
const functionForResponse = "const response = await fetch(url, options);";
// const response = await fetch(url, options);
// const data = await response.json();
res.status(200).json({
status: "success",
token,
options,
url,
organisation,
functionForResponse,
});
} catch (err) {
console.log(err);
res.status(500).json({
err,
});
}
};
When I uncomment these 2 lines in the above controller
const response = await fetch(url, options);
const data = await response.json();
I get this result
https://vp-expo-node-server.herokuapp.com/eticket/response
As I don't know how to display the error on the browser I tried to console.log it and I got this error in the console
TypeError: Request with GET/HEAD method cannot have body
at new Request (/Applications/MAMP/htdocs/vp-expo-node-server/node_modules/node-fetch/lib/index.js:1199:10)
at /Applications/MAMP/htdocs/vp-expo-node-server/node_modules/node-fetch/lib/index.js:1409:19
at new Promise (<anonymous>)
at fetch (/Applications/MAMP/htdocs/vp-expo-node-server/node_modules/node-fetch/lib/index.js:1407:9)
at exports.addOneExhibitorToCreatorResponse (/Applications/MAMP/htdocs/vp-expo-node-server/controllers/eticketController.js:82:28)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
And I can confirm that the this line in the console.log
at exports.addOneExhibitorToCreatorResponse (/Applications/MAMP/htdocs/vp-expo-node-server/controllers/eticketController.js:82:28)
points to the uncommented lines...
So there's something wrong I am doing in those 2 lines.. but according to me it's the right way to send a POST request.. and I have no clue how a POST request can get a Request with GET/HEAD method cannot have body error.
Any help would be appreciated. I've double checked it and I've even asked Zoho for help (they mentioned as it's a client side thing they couldn't do much to help)
I've got my answer in the comments but just posting an answer just in case someone else is facing 'REQUEST WITH GET/HEAD METHOD' error when trying to send a POST request.
As #CherryDT pointed out in my case the POST method was not being used as I had misspelt 'method' as 'Method' (and I had committed the same mistake with 'headers' as 'Headers')..
So the 'method' property was not being used at all and it was defaulting to 'GET'... and hence the error.

Netlify function: GitHub API proxy request fails with `error decoding lambda response: json`

This Netlify function should run as an endpoint on example.com/.netlify/functions/github and is supposed to proxy a fetch request from my website, reach out to the GitHub API and send data back to the website.
As far as I have understood, I can use to GET data from the GitHub API without authentication. Hitting their API directly in the browser works: https://api.github.com/orgs/github/repos?per_page=2 (also works from Postman).
The data is an array of objects where each object is a repository.
There has been multiple issues the past couple of years where Netlify functions (running on AWS lambdas) have had hickups that resulted in error messages similar to mine, so I'm confused whether this is an error in my code or something weird on their side.
First, the proxy function which – according to the Netlify admin console – runs without error. In a support article Netlify requires the result returned as JSON.stringify(), so I follow that convention here:
const fetch = require('node-fetch')
const url = 'https://api.github.com/orgs/github/repos?per_page=2'
const optionsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
}
const fetchHeaders = {
'Content-Type': 'application/json',
'Host': 'api.github.com',
'Accept': 'application/vnd.github.v3+json',
'Accept-Encoding': 'gzip, deflate, br'
}
exports.handler = async (event, context) => {
if (event.httpMethod === 'OPTIONS') {
return {
'statusCode': '200',
'headers': optionsHeaders,
}
} else {
try {
const response = await fetch(url, {
method: 'GET',
headers: fetchHeaders
})
const data = await response.json()
console.log(JSON.stringify({ data }))
return {
statusCode: 200,
body: JSON.stringify({ data })
}
} catch (err) {
console.log(err)
}
}
}
Client fetch that hits https://example.com/.netlify/functions/github. URL is correct, the function is executed (verified that in the Netlify admin panel):
const repos = document.querySelectorAll('.repo')
if (repos && repos.length >= 1) {
const getRepos = async (url) => {
try {
const response = await fetch(url, {
method: "GET",
mode: "no-cors"
})
const res = await response.text()
// assuming res is now _text_ as per `JSON.stringify` but neither
// that nor `.json()` work
console.log(res[0].name)
return res[0].name
} catch(err) {
console.log(err)
}
}
const repoName = getRepo('https://example.com/.netlify/functions/github')
repos.forEach((el) => {
el.innerText = repoName
})
}
Not 100% sure where this error message originates from, it is probably not the console.log(err) although it displays in the browser console, because the error code is 502 and the error also shows up directly in the response body in Postman.
error decoding lambda response: error decoding lambda response: json: cannot unmarshal
string into Go value of type struct { StatusCode int "json:\"statusCode\""; Headers
map[string]interface {} "json:\"headers\""; MultiValueHeaders map[string][]interface {}
"json:\"multiValueHeaders\""; Body string "json:\"body\""; IsBase64Encoded bool
"json:\"isBase64Encoded,omitempty\""; Metadata *functions.Metadata
"json:\"metadata,omitempty\"" }
Haven't found any clear information on this issue, could any of you enlighten me?
The only response that don't comply with the schema is the preflight request. From the error message, I assume you need to change:
'statusCode': '200',
to
'statusCode': 200, // StatusCode int
Even better, because there's no content, you may want to use 204 instead.
If that's still not enough, I may still want to include the body there as well, as it doesn't seem optional:
return {
'statusCode': 204,
'headers': optionsHeaders,
'body': ''
}

How to return object instead of string for response with nock?

When I stub request with nock it returns String result instead of Object even with 'Content-Type': 'application/json':
var response = {
success: true,
statusCode: 200,
body: {
"status": "OK",
"id": "05056b27b82",
}
};
Test.BuildRequest();
Test.SendRequest(done);
nock('https://someapi.com')
// also tried
// .defaultReplyHeaders({
// 'Content-Type': 'application/json',
// 'Accept': 'application/json'
// })
.post('/order')
.reply(200, response.body,
'Content-Type': 'application/json',
'Accept': 'application/json');
checking:
console.log(put.response.body);
console.log(put.response.body.id);
output:
{"status":"OK","id":"05056b27b82"}
undefined
In code I use request module that returns Object with the same data. I tried also sinon (doesn't work for me) and fakeweb but got the same issue.
My code, which i'm trying to test:
var request = require('request');
// ...
request(section.request, function (err, response, body) {
if (err || _.isEmpty(response))
return result(err, curSyndication);
//if (_.isString(body))
// body = JSON.parse(body);
section.response.body = body;
console.log(body.id); // => undefined (if uncomment previous code - 05056b27b82)
_this.handleResponse(section, response, body, result);
});
And it returns an object in real requests.
PS. I could add next code in my response handler:
if (_.isString(body))
body = JSON.parse(body);
But some of queries returns xml string, and i'm not responsible for such changes.
Fakeweb:
fakeweb.registerUri({
uri: 'https://someapi.com/order',
body: JSON.stringify({
status: "OK",
id: "05056b27b82",
}),
statusCode: 200,
headers: {
'User-Agent': 'My requestor',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
Test.SendRequest(done);
Same results.
Updated:
I read a couple of articles, that uses JSON Object, without parsing it (with nock), so it should returns JSON object, same way how request library do that.
There is nothing wrong with your nock configuration however you haven't told request to parse the response as JSON.
From the request method documentation (emphasis on me):
json - sets body but to JSON representation of value and adds Content-type: application/json header. Additionally, parses the response body as JSON.
The callback argument gets 3 arguments:
An error when applicable (usually from http.ClientRequest object)
An http.IncomingMessage object
The third is the response body (String or Buffer, or JSON object if the json option is supplied)
So you need to set the json property to true on your section.request object:
var request = require('request');
// ...
section.request.json = true;
request(section.request, function (err, response, body) {
//..
});

Categories