Express res.send or res.json doesn't contain a body - express

I'm calling an API to fetch orders for a given user based on ID which are fetched from a third-party site. These are fetched correctly as a console.log them in the node server. But when I try to send the results back to the client neither res.send nor res.json results sending the data back to the client. Here is an example of an order from console.log:
{"customer":{"orders":{"edges":[{"node":{"id":"gid://shopify/Order/1234564564","lineItems":{"edges":[{"node":{"title":"Some title here"}}]}}}]}}}
Then on the client in the devtools when I console.log the response I get:
body:ReadableStream
locked:false
[[Prototype]]:ReadableStream
bodyUsed:false
headers:
Headers {}
ok:true
redirected:false
status:200
statusText:"OK"
type:"basic"
url:"http://localhost:9000/api/getOrders?cid=gid://shopify/Customer/1234564564"
[[Prototype]]:Response
Any help is appreciated.
=== UPDATE ===
I've now even tried the most basic of examples and am getting the same response on the client:
app.get('/testExpress', (req, res) => {
res.send("Hello")
});
Thanks to #laurent here is how I was able to receive that response on the client:
fetch('/testExpress')
.then(async (r) => {
const resp = await r.text();
console.log(resp);
})

You should try to get the json out of the response by const json = await response.json().
These are the available methods to parse the response body depending on what you want:
Response.arrayBuffer()
Returns a promise that resolves with an ArrayBuffer representation of the response body.
Response.blob()
Returns a promise that resolves with a Blob representation of the response body.
Response.clone()
Creates a clone of a Response object.
Response.formData()
Returns a promise that resolves with a FormData representation of the response body.
Response.json()
Returns a promise that resolves with the result of parsing the response body text as JSON.
Response.text()
Returns a promise that resolves with a text representation of the response body.
https://developer.mozilla.org/en-US/docs/Web/API/Response
The Response object is a representation of the http response. You should try to receive the body of the response by using one of these methods or parsing the body from the readable stream response.body.

Related

Set cookie after fetch request response from auth server

I just started learnign about the express library, im developing an app that access restricted info about a user using an Eve Online API, to do this the user is redirected to an authentication page to get an access and refresh token.
Everything works fine until I try to pull the 'refresh_token' from the response and set a cookie with it.
The error:
(node:20600) UnhandledPromiseRejectionWarning: TypeError: res.cookie is not a function
My code:
const url = 'https://login.eveonline.com/v2/oauth/token';
const options = {
'method':'POST',
headers:
{
'authorization':'Basic '+ process.env.ENV_PASS,
'Content-Type':'application/x-www-form-urlencoded',
'host':'login.eveonline.com'
},
body:''
}
function send_get_request(req, res){
options.body =`grant_type=authorization_code&code=${req.query.code}`
fetch(url,options,{credentials:'include'})
.then(handle_stream)
.then(handle_json)
.then(set_cookie)
.then(redirect_home)
}
function handle_stream(res){
return res.json() //handless data stream, returns responce
}
function handle_json(res){
return res.refresh_token
}
function set_cookie(res){
return res.cookie('refresh_token','hello')
}
function redirect_home(res){
res.redirect('http://localhost:3000/home')
}
router.get('/',send_get_request)
I tried breaking the .then() block but still res.cookie doesn't exits. Also tried using credentials but it doesn't work.
Your code contains two variables res: One stands for the response that your middleware sends back to the client, the other stands for the response you are receiving from the fetch operation. Only the handle_stream function operates on the latter, whereas set_cookie and redirect_home operate on the former.
The last three function are also synchronous and need not be chained with .then. The are invoked synchronously in a function that takes as parameter the json which handle_stream produces asynchronously.
function send_get_request(req, res){
options.body =`grant_type=authorization_code&code=${req.query.code}`;
fetch(url,options,{credentials:'include'})
.then(handle_stream)
.then(function(json) {
var refresh_token = handle_json(json);
set_cookie(res, refresh_token);
redirect_home(res);
});
}
It is all perhaps easier to understand with the async-await syntax:
async function send_get_request(req, res){
options.body =`grant_type=authorization_code&code=${req.query.code}`;
var response = await fetch(url,options,{credentials:'include'});
var json = await handle_stream(response);
var refresh_token = handle_json(json);
set_cookie(res, refresh_token);
redirect_home(res);
}

How to read the contents of a Post request on Postman?

In the systems I am testing, there are cases that the response informs 200 (ok), but the content may indicate an error in the internal validations of the backend service. How can I read the contents of the response with Postman and schedule a successful validation if this service error code comes as expected?
You can use the tests tab in Postman to run checks on the body (JSON and XML). There are snippets which show you the syntax. You can adapt them to check for the element of the response body which indicates the error.
Postman has a tab called "Tests" where you can provide you test script for execution.
If you want to validate your request responded with 200 OK, following is the script
pm.test("Status test", function () {
pm.response.to.have.status(200);
});
If you want to validate the response contains any specified string,
pm.test("Body matches string", function () {
pm.expect(pm.response.text()).to.include("string_you_want_to_search");
});
In your case am assuming the above script can be used. In case the response body is JSON,
pm.test("JSON Body match", function () {
var respBody = pm.response.json();
pm.expect(respBody.<json node>).is.to.equal("Error_name");
});
Example JSON response body
{
"id" : 100,
"status" : "Bad Request"
}
pm.test("JSON Body matches string", function () {
var respBody = pm.response.json();
pm.expect(respBody.status).is.to.equal("Bad Request");
});

How to get the data associated with the error response back?

I am making a request from the front-end to a route in my backend that is validating the token associated with a user, which would send an error response back to the front-end if the token has expired. I am sending some json with it but upon doing console.log of the error message in the catch block, the json sent along the error response is not shown.
Sending the error response like this
res.status(401).json({
message: 'User session has expired'
})
But the response that I am getting in the catch block in the front-end has no sign of the json sent with the error.
POST http://localhost:3001/check-validation 401 (Unauthorized)
Error: Request failed with status code 401
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
I don't understand why the json sent along the error response is not shown and how to get it?
Upon doing console.log of the error only the stacktrace of the error is shown and not the data associated with it. The data sent with it can be procured and depends on how the request has been made or by what library it has been made. If the request is made by axios then the following can be done:
axios.post('/formulas/create', {
name: "",
parts: ""
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error.response.data.message)
});
Here, in axios the details of the error would be wrapped up in error.response. Whereas, if the request was made by the fetch API then something following can resolve the problem:
fetch('/401').then(function(response) {
if (response.status === 401) {
return response.json()
}
}).then(function(object) {
console.log(object.message)
})
P.S I was searching a lot regarding this problem but didn't get an answer on SO, neither got any article or docs regarding it, even the official Express docs on error handling were not helpful. At last, I understood that the problem lies with the library that is being used to make the request. That's why answering my own question to mark the presence of this question on SO. A detailed discussion can be found here related to axios and here related to fetch api

Express JS - Handling POST request

I am having trouble interpreting the following POST request sent via Postman in Express.js: (sending "temp": 97.7, "device": "one")
My POST router (in ./routes/sensors) is a simple
router.post('/', function(req, res, next) {
console.log(req.body)
});
and my index.js contains
var sensorsRouter = require('./routes/sensors');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/sensors', sensorsRouter);
Question: When I send the above mentioned POST request, my console understands it's a POST, but the output of req.body is empty: {}
How can I interpret the "temp" and "device" sent as a POST request in Express.js? I found many instructions involving body-parser, but as far as I understand express.json and express.urlencoded are supposed to be used instead these days.
As i see your postman settings are wrong.you are sending data as GET data in the URL even you set request type as POST. Here is my POST setting for once of my api.
1.set header content-type as application/json
2.In the body tab select raw option and json/application from dropdown box. Then give your data as json object

Sailsjs socketio http status

I know I can call REST API of sails using socket.io. And return me the response. Following is a simple way to do that
socket.get("/", function (response) { console.log(response); })
But I also want the http status code along with response how I can get that?
If you're using the API blueprints, then the response will return the status code in the event of an error. For example, if there was a general server error, you'll get back:
{status: 500}
Otherwise, you'll get data in the response and you can assume the status was 200.
If you're using a custom controller action, then you can use any of the default responses (like res.serverError(), res.forbidden(), etc) to send back a status code, or you can set one yourself:
myAction: function (req, res) {
return res.forbidden(); // Will send {status: 403}
// OR
return res.json({status:400, error: 'Bad request!'})
}
But if you just send the status using res.json(500, {error: 'someError'}), you won't be able to retrieve it on the client.
Update
On Sails v0.10.x, using the new Sails socket client library, the request methods (io.socket.get, io.socket.post, etc) have callbacks that accept two arguments: the first being the response body (equivalent to the response in the previous client library version), and the second being an expanded response object which includes the status code, headers and more.