Can't read body of request but can print it - node.js

I am pulling my hairs off. On http request, i can print a body object but can not access its content.
So i am sending a request like this from web:
return fetch('https:xxxxxxx/xxxx', {
method: 'post',
body: JSON.stringify(saleObject),
headers: {
'Accept': 'application/json',
'contentType':"application/json",
'dataType':"json",
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID;
});
}
On my server (nodejs express Firebase ) , I am trying to read it in multiple ways :
exports.payPalIntent = functions.https.onRequest(async(req, res) => {
return cors(req, res, async () => {
console.log("req.body",req.body); //this print AN OBJECT, A REAL OBJECT NOT A STRING
console.log("req address",req.body.address); //=undefined, there is address property inside which
return res.send(200);
});
So, the first one print this :
req.body {"address":{"city":"some city","zip":"345334","area":"USA","street":"Hai 13", ........
The second says Cannot read property 'address' of undefined
Of course, i tried also JSON.stringify(req.body) , which print a string object that i can't access.
How do you access this object ?

JSON.stringify turns a JavaScript object into a JSON string. You already have a JSON string and you want to covert it to a JavaScript object, so use the reverse: JSON.parse(req.body). Then you should be able to access the properties using the dot operator.

Related

Angular Convert POST request data to array

I have a post request that sends some data to a NodeJS app and then that returns an array. My problem is that I can't turn the data I receive as a response from the POST request to an array.
My Angular is set up like this:
newWord = '';
keyword = '';
onClick() {
const headers = new HttpHeaders()
.set('Authorization', 'my-auth-token')
.set('Content-Type', 'application/json');
this.http.post('http://localhost:3000/search',
{ keyword: this.keyword },
{
headers: headers
})
.subscribe((data) => {
console.log(data);
})
}
}
The data inside the node app looks like this:
I want to get this data in angular as an array so I can iterate over it or do anything else with the fields. Any help would be appreciated!
Provide the type to the http request. Otherwise angular expects any, which is not necessarily an array. That is where the error comes from.
this.http.post<{ id: string, text: string }[]>('http://localhost:3000/search',
{ keyword: this.keyword },
{
headers: headers
})
.subscribe((data) => {
console.log(data);
})

How to check for plain text response from a POST request?

I'm trying to use frisby.js to specify an API test for an endpoint that returns a plain text response to a valid POST request. However I'm having problems getting frysby.js to accept non-JSON response documents. Whenever a response returns non-JSON content, throw a TypeError due to 'Unexpected token b in JSON at position 0'.
As an example, I'm sending a HTTP POST request with the JSON document shown below is expected to return a response with a plaintext document with the string bar.
{
"foo":{
"name":"bar"
}
}
Here's the unit test that I've wrote to verify the response:
it('should create a foo resource', function () {
return frisby.post('http://localhost:8080/',
{
"foo":{
"name":"bar"
}
})
.expect('status',201);
});
Unfortunately, the following error is thrown by frisby.js when I run the test:
FAIL ./test.js
✕ should create a foo resource (17ms)
● should create a foo resource
TypeError: Invalid json response body: 'bar' at http://localhost:8080/ reason: 'Unexpected token b in JSON at position 0'
Does anyone know if it's possible to configure each test to expect some data format other than JSON?
If you getting JSON + something then break jsonTypes in two format like one for JSON object and one for other, like it having array in JSON objects.
and then put expect conditions on them.
This might helps you:
const frisby = require('frisby');
const Joi = frisby.Joi;
frisby.globalSetup({
headers : {
"Accept": "application/json",
"content-type" : "application/json",
}
});
it("should create a foo resource", function () {
frisby.post("http://localhost:8080/")
.expect("status", 200)
.expect("header", "content-type", "application/json; charset=utf-8")
.expect("jsonTypes", "data.foo", {
"name": Joi.string()
})
.then(function(res) { // res = FrisbyResponse object
var body = res.body;
body = JSON.parse(body);
expect(body.data.foo.name).toBeDefined();
})
});

Cypress : how to forward response body JSON to be used on headers

i'm gonna test REST API using Cypress.io , but using chaining request, it wants to be work like this, JSON response body on the first API will be used on the next API Headers for Authorization
I'm already try doing by using cypress commands and printing on console.log, but seems like it does not captured on the log, or is there any clue for this, or i just using another command like cy.route ?
Cypress.Commands.add("session", () => {
return cy.request({
method: 'POST',
url: '/auth/',
headers: {
'Content-Type': 'application/json',
},
body: {
"client_secret" : ""+config.clientSecret_staging,
"username": ""+config.email_staging,
"password": ""+config.password_staging
}
}).then(response => {
const target = (response.body)
})
})
it('GET /capture', () => {
cy.session().then(abc =>{
cy.request({
method: 'GET',
url: '/capture/'+target
})
})
})
the goal is to capture parse of JSON array from target = (response.body)
You have two options:
leave the code as is, be aware that the
.then(response => {
const target = (response.body)
})
code isn't returning anything so the cy.session().then(abc =>{ ... code is getting the whole response (abc is the response of the first .then)
change the code into
.then(response => {
const target = (response.body)
return target // I added this return
})
and then your abc param will be equal to response.body and not to response
That's because if you don't return a subject from your chainable calls the default one will be passed to the next .then function.
Let me know if it satisfies your issue.
p.s. Welcome 👋

nodejs - first argument must be a string or Buffer - when using response.write with http.request

I'm simply trying to create a node server that outputs the HTTP status of a given URL.
When I try to flush the response with res.write, I get the error: throw new TypeError('first argument must be a string or Buffer');
But if I replace them with console.log, everything is fine (but I need to write them to the browser not the console).
The code is
var server = http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type": "text/plain"});
request({
uri: 'http://www.google.com',
method: 'GET',
maxRedirects:3
}, function(error, response, body) {
if (!error) {
res.write(response.statusCode);
} else {
//response.end(error);
res.write(error);
}
});
res.end();
});
server.listen(9999);
I believe I should add a callback somewhere but pretty confused and any help is appreciated.
I get this error message and it mentions options.body
I had this originally
request.post({
url: apiServerBaseUrl + '/v1/verify',
body: {
email: req.user.email
}
});
I changed it to this:
request.post({
url: apiServerBaseUrl + '/v1/verify',
body: JSON.stringify({
email: req.user.email
})
});
and it seems to work now without the error message...seems like bug though. I think this is the more official way to do it:
request.post({
url: apiServerBaseUrl + '/v1/verify',
json: true,
body: {
email: req.user.email
}
});
response.statusCode is a number, e.g. response.statusCode === 200, not '200'. As the error message says, write expects a string or Buffer object, so you must convert it.
res.write(response.statusCode.toString());
You are also correct about your callback comment though. res.end(); should be inside the callback, just below your write calls.
Request takes a callback method, its async! So I am assuming, by the time the callback is executed the res.end() might get called. Try closing the request within the callback.
Well, obviously you are trying to send something which is not a string or buffer. :) It works with console, because console accepts anything. Simple example:
var obj = { test : "test" };
console.log( obj ); // works
res.write( obj ); // fails
One way to convert anything to string is to do that:
res.write( "" + obj );
whenever you are trying to send something. The other way is to call .toString() method:
res.write( obj.toString( ) );
Note that it still might not be what you are looking for. You should always pass strings/buffers to .write without such tricks.
As a side note: I assume that request is a asynchronous operation. If that's the case, then res.end(); will be called before any writing, i.e. any writing will fail anyway ( because the connection will be closed at that point ). Move that line into the handler:
request({
uri: 'http://www.google.com',
method: 'GET',
maxRedirects:3
}, function(error, response, body) {
if (!error) {
res.write(response.statusCode);
} else {
//response.end(error);
res.write(error);
}
res.end( );
});
if u want to write a JSON object to the response then change the header content type to application/json
response.writeHead(200, {"Content-Type": "application/json"});
var d = new Date(parseURL.query.iso);
var postData = {
"hour" : d.getHours(),
"minute" : d.getMinutes(),
"second" : d.getSeconds()
}
response.write(postData)
response.end();
And there is another possibility (not in this case) when working with ajax(XMLhttpRequest), while sending information back to the client end you should use res.send(responsetext) instead of res.end(responsetext)
Although the question is solved, sharing knowledge for clarification of the correct meaning of the error.
The error says that the parameter needed to the concerned breaking function is not in the required format i.e. string or Buffer
The solution is to change the parameter to string
breakingFunction(JSON.stringify(offendingParameter), ... other params...);
or buffer
breakingFunction(BSON.serialize(offendingParameter), ... other params...);
The first argument must be one of type string or Buffer. Received type object
at write_
I was getting like the above error while I passing body data to the request module.
I have passed another parameter that is JSON: true and its working.
var option={
url:"https://myfirstwebsite/v1/appdata",
json:true,
body:{name:'xyz',age:30},
headers://my credential
}
rp(option)
.then((res)=>{
res.send({response:res});})
.catch((error)=>{
res.send({response:error});})

How to post multipart/form-data with node.js superagent

I am trying to send the content-type in my superagent post request to multipart/form-data.
var myagent = superagent.agent();
myagent
.post('http://localhost/endpoint')
.set('api_key', apikey)
.set('Content-Type', 'multipart/form-data')
.send(fields)
.end(function(error, response){
if(error) {
console.log("Error: " + error);
}
});
The error I get is:
TypeError: Argument must be a string
If I remove the:
.set('Content-Type', 'multipart/form-data')
I don't get any error but my back end is receiving the request as content-type: application/json
How can I force the content type to be multipart/form-data so that I can access req.files()?
First, you do not mention either of the following:
.set('Content-Type', 'multipart/form-data')
OR
.type('form')
Second, you do not use the .send, you use .field(name, value).
Examples
Let's say you wanted to send a form-data request with the following:
two text fields: name and phone
one file: photo
So your request will be something like this:
superagent
.post( 'https://example.com/api/foo.bar' )
.set('Authorization', '...')
.accept('application/json')
.field('name', 'My name')
.field('phone', 'My phone')
.attach('photo', 'path/to/photo.gif')
.then((result) => {
// process the result here
})
.catch((err) => {
throw err;
});
And, let's say you wanted to send JSON as a value of one of your fields, then you'd do this.
try {
await superagent
.post( 'https://example.com/api/dog.crow' )
.accept('application/json')
.field('data', JSON.stringify({ name: 'value' }))
}
catch ( ex ) {
// .catch() stuff
}
// .then() stuff...
Try
.type('form')
instead of
.set('Content-Type', 'multipart/form-data')
See http://visionmedia.github.io/superagent/#setting-the-content-type
It is not clear what is in the fields variable that you are sending, but here is some information that may help you determine where your problem lies.
To begin with, if you are actually trying to build a multi-part request, this is the official documentation for doing so: http://visionmedia.github.com/superagent/#multipart-requests
as for the error that you got...
The reason is that during the process of preparing the request, SuperAgent checks the data to be sent to see if it is a string. If it is not, it attempts to serialize the data based on the value of the 'Content-Type', as seen below:
exports.serialize = {
'application/x-www-form-urlencoded': qs.stringify,
'application/json': JSON.stringify
};
which is used here:
// body
if ('HEAD' != method && !req._headerSent) {
// serialize stuff
if ('string' != typeof data) {
var serialize = exports.serialize[req.getHeader('Content-Type')];
if (serialize) data = serialize(data);
}
// content-length
if (data && !req.getHeader('Content-Length')) {
this.set('Content-Length', Buffer.byteLength(data));
}
}
this means that to set a form 'Content-Type' manually you would use
.set('Content-Type', 'application/x-www-form-urlencoded')
or
.type('form') as risyasin mentioned
any other 'Content-Type' will not be serialized, and Buffer.byteLength(data) will subsequently throw the TypeError: Argument must be a string exception if the value of your fields variable is not a string.
Here is what worked for me. I had a single field form, that was uploading a file. I turned the form into a HTML5 FormData element and then did it as follows:
var frm = new FormData(document.getElementById('formId'));
var url = 'url/here';
superagent.post(url)
.attach('fieldInFormName', frm.get('fieldInFormName'))
.end( function (error, response) {
//handle response
});
Please note, I tried various ways of setting the 'Content-Type' manually in superagent, and it never worked correctly because of the multipart identifier needed in the Content-Type.

Resources