Cannot GET from Express.js PUT route, why? - node.js

Is there any reason you cannot execute a GET request from inside an Express.js router.put()?
I have two routes. The exact same api call works in a router.get() route and hangs in the router.put().
I've confirmed that
This works:
router.get('/:id', async (req, res) => {
const { headers } = req;
let result;
try {
result = await axios({ method:'get', url: '/some-url', headers });
} catch(error) {
res.status(500).send(new Error('myError');
}
res.send({ result });
});
This does NOT work:
router.put('/:id', async (req, res) => {
const { headers } = req;
let result;
let finalResult;
try {
result = await axios({ method:'get', url: '/some-url', headers });
} catch(error) {
res.status(500).send(new Error('myError');
}
// logic based on the result of the above GET determines what the value of `finalResult`
finalResult = { some: 'data' };
res.send({ finalResult });
});
Even though axios({ method:'get', url: '/some-url' }) is the exact same in both routes, it works in one and not the other.
The router.put() route always hangs for a long time and eventually Node outputs:
Error: socket hang up, code: 'ECONNRESET', etc...
Appreciate any help, I've spent over a day scratching my head over this.

No there's no such thing in express. Try hitting the GET request from postman or curl and see if response is coming. The root cause could be an invalid get request you're trying to make or that server on which you are making GET request could be down. You can run following to validate
app.put('/',async (req, res) => {
let response = await axios.get('https://google.co.in');
console.log(response.data);
res.send({"works": "hello"});
});

Root cause of my problem:
The http Headers had a key of Content-Length that prevented GET calls to resolve correctly.
Since these api calls occurred within a router.put() callback, the Headers had a Content-Length pointing to the size of the payload "body" that was being PUT to begin with.
Solution:
Remove that Content-Length field from my Headers when doing GETs inside router.put(), such that the GET has all the other Headers data except for Content-Length
Unfortunately, NodeJS just threw that Error: socket hang up message that was not very descriptive of the underlying problem.

Related

Axios POST request sending but not being recieved

I know this has been asked before but any solutions I've tried have failed to get results so far. I'm new to Axios and I'm trying to test sending a POST request, and it seems like the request is indeed sent, but it never ends up actually being received, despite showing a 200 OK status code. I've been troubleshooting a while, but no amount of changing headers or fiddling with the server seems to have changed anything.
Sending Request
handleSubmit(event){
event.preventDefault();
var myObj = {
email: this.state.userEmail,
password: this.state.userPassword,
failedLogin: this.state.failedLogin
}
// validate login
axios.post("/login", myObj)
.then(function(response){
console.log(response.data.test);
})
.catch(function (error) {
console.log(error);
});
}
Receiving Request
The alert with "receive" is never executed.
userRoutes.route("/login").post((req, res) => {
console.log("sent");
res.send({test: "test"})
});
And my requests/responses and console:
request
response
console
Axios signature for post is axios.post(url[, data[, config]]). So your object should be written as 3rd parameter. Also, your post url must be complete. Otherwise you will get invalid url error.
Sending Request
axios
.post("http://localhost:3000/login", null, yourObj)
.then((res) => {
console.log(res.data.test);
// Result: test
})
.catch((err) => console.log(err));
Receiving Request
app.post("/login", (req, res) => {
res.status(200).json({ test: "test" });
});
Sure enough, as #Phil and #trognanders suggested, the problem was because my Express middleware was configured incorrectly, hence not an Axios problem.

Using a proxy with node fetch is returning 403 on some endpoints

I'm trying to use a proxy with node fetch to grab data from an api. It works fine on lumtest.com
const url = 'https://lumtest.com/myip.json';
When I'm trying to get a response from my own express test api or typicode I get the following error, note that removing the proxy agent returns the correct json response so i'm leading towards missing headers but I have also tried adding in user-agent, method, content-type but no luck:
FetchError: invalid json response body at http://localhost:8000/api/test reason: Unexpected end of JSON input
The test api in express is super simple
router.get('/test', (req,res) => {
res.json({
msg: 'Success'
})
})
The call im making with the proxy looks like the following
async function getData() {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
try{
const response = await fetch(url, {
agent: new HttpsProxyAgent.HttpsProxyAgent(`https://username-zone-data_center:pass#zproxy.lum-superproxy.io:22225`)
});
const json = await response.json();
console.log('json', json);
} catch (e) {
console.log('Error: ', e)
}
}
Changing the url to const url = 'https://lumtest.com/myip.json' or https://httpbin.org/ip?json works though...
Any suggestions appreciated.

I cant get a response from a POST request with an array in the body, Using NodeJS / Axios and Postman

This is a course quiz and this is the most basic information I need in order to create a React app. But while the endpoint URL is correct, the page "/products" returns a "400" error when I try to request the product list. The instructions I'm given are:
Obtain a list of products with
Route: /products
Body: Array
method: POST
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
My index.js
...
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`);
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
in Postman
I use http://localhost:4000/products
and pass a Body / Raw /JSON:
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
But I can't get in! I am not seeing something obvious because this is the entry point to a very long and complex quiz. Thanks
What I see from the code is a recursive long call.
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`); // calling the same end point
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
You should do something like this:
app.post(`/products`, async (req, res) => {
// do your logic
// when you pass body from postman on this endpoint
// you will receive the body here and save it to DB
// or do the manipulation and then send back the response
res.status(200).json(req.body.data);
});
I highly recommend you to first follow through some tutorials to understand how API works and how to create simple API using Node.js.

How to evaluate API response from server and act accordingly at client side using Fetch() and Node.js

I fetch data at server side and push the result to global variable and then send that global variable to client with app.post method using Express.js. My problem is that client fetches the global variable too soon without the data received from the API first. How can I evaluate the response so that client would wait the global variable to reveive data first before displaying anything.
Server side, code looks something like this:
let sharpe = ''
app.post('/api', async(req, res, next) => {
console.log('I got a request!')
thisOne = req.body.stock1
thisOne2 = req.body.stock2
var result = await setup();
res.json({
status: 'success',
stocks: sharpe
});
})
Sharpe is the global variable storing the response from multiple API calls and is the one that should be sent back to client. Client side code is this:
const sendData = async (event) => {
event.preventDefault();
var stock1 = document.getElementById('weight1').value
var stock2 = document.getElementById('weight2').value
const data = {stock1, stock2};
const options = {
method: 'POST',
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json' }
}
fetch('/api', options).then(res => res.json()).then(res => {
console.log(res.stocks);
})
}
As a result SendData() function fetches the sharpe variable that is empty at the moment. How can I adjust client side code or server side code that the client waits for a correct response? Thanks.
One solution would be to store the API results to database and client would fetch ready made datastream but is there more straightforward solution?
To wait for your API Server to set the sharpe Parameter, it needs to be awaited, which you already did. It depends on the setup function (for example setup()) which fills the sharpe parameter. It has to return a promise, which is resolved once sharpe is filled with the data.
let sharpe = ''
async setup() {
return new Promise((resolve, reject) => {
sharpe = 'test';
// set value for sharpe
resolve()
})
}
app.post('/api', async(req, res, next) => {
console.log('I got a request!')
thisOne = req.body.stock1
thisOne2 = req.body.stock2
var result = await setup();
res.json({
status: 'success',
stocks: sharpe
});
})
Eventually it starded working when I pushed all the API calls in the app.post middleware at the server side using promise chaining. The initial problem remains a mystery.

Conditional redirect with express / request-promise

I am rather new with express together with the request-promise module,
and need to create a service S
that is called from serverA
and after S has asked ServerB for some additional info,
it redirects the request of serverA to ServerC.
Since I get a
Error: Can't set headers after they are sent.
even though I do not add something by myself, I wonder someone could help me to get this workflow straight.
This is the code:
`
const express = require('express')
const rp = require('request-promise')
...
app.get('/dispatch', cors(), (req, res, next) => {
var options = {
uri: 'https://ServerB/calc-something..',
headers: {
'User-Agent': 'its-me',
'Data': data_from_serverA
},
resolveWithFullResponse: true, // Get statuscode
json: true // Parse the JSON string in the response
};
rp(options) // Do request to serverB
.then(function (response) {
console.log(`ServerB responded with statuscode ${response.statusCode}`)
// No error, so redirect original res
res.redirect('https://serverC/...') // error occurs here
return next(response)
})
.catch(function (err) {
console.log(`ServerB responded with error ${err}`)
return next(err) // send 500 to serverA
})
})
`
Your cors() middleware is setting CORS headers. This is causing the headers to be sent while your promise is resolving.
A redirect ALSO sends headers, and this is the issue. A redirect sets a location header, but you've already sent the headers so that won't work.
The solution is to split your final middleware into two. First, check to see if a redirect is needed and if so, do that. Otherwise, set whatever data you need on the req object and handle this AFTER the cors call.
Your final route will look something like:
app.get('/dispatch', checkRedirect, cors(), (req, res, next) => {
//do something useful, or send your error
})
The contents of your checkRedirect function will be pretty similar to what you have above. However, you do not pass data to the next() function. That just passes control to the next middleware. Instead, put any data you need on the req object and handle it in the final middleware, AFTER cors. If all you are doing is setting a 500 error, you don't even need CORS for that.
According to #Rampant 's answer,
this is how I did it with request-promise (rp):
function checkPrecondition(req, res, next){
req.precondition = false
rp({ method: 'POST',
...
})
.then((data) => {
...
req.precondition = true
next()
})
.catch((data) => {
...
next()
})
}
and in the express handler:
app.post('/query', checkPrecondition, cors(), (req, res, next) => {
if(!req.precondition){
res.status(400).send(JSON.stringify({status: 'insufficient'}))
return
}
res.redirect('target.host')
})
Thanks for clearifying the CORS issue.

Resources