Cannot set headers after they are sent to the client? - node.js

Here I'm trying to GET data from server, But when I try to open the browser and get the data nothing appear, Its give me the same URL in the browser.
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]:
// Application Dependencies
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const superAgent = require('superagent');
// Application Setup
const PORT = process.env.PORT || 3000;
const app = express();
app.use(cors());
//KEYS
const WEATHER_API_KEY = process.env.WEATHER_API_KEY;
const GEOCODE_API_KEY = process.env.GEOCODE_API_KEY;
const PARK_KEY = process.env.PARK_KEY;
//Route Definitions
app.get('/location', locationHandler);
app.get('/weather', weatherHandler);
app.get('/parks', parksHandler);
app.get('*', errorHandler);
//Location Handler
async function locationHandler(req, res) {
try {
console.log(req.query);
let getCity = req.query.city;
let url = `https://us1.locationiq.com/v1/search.php?key=pk.9e079e96352c63d18cf387532fa6b9ad&q=seattle&format=json`;
const locationData = await superAgent.get(url);
const apiData = JSON.parse(locationData.text);
console.log(superAgent.get(url))
res.send(superAgent.get(url));
// let aaa = new City(getCity, apiData[0].display_name, apiData[0].lat, apiData[0].lon);
// console.log(aaa);
res.status(200).send(new City(getCity, apiData[0].display_name, apiData[0].lat, apiData[0].lon));
} catch (error) {
res.status(404).send('Something went wrong in LOCATION route')
}
}

The response object does not batch an entire response necessarily, and might start sending it as available. HTTP requires that headers are written before anything else. Once anything else is written, it becomes impossible to send headers, such as changing the status code.
You might refactor the code to send the status first:
res.status(200)
res.send(superAgent.get(url));
res.send(new City(getCity, apiData[0].display_name, apiData[0].lat, apiData[0].lon));
} catch (error) {

You cannot send a response more then once.
So remove this line: res.send(superAgent.get(url));

Related

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client - Node.Js, Express, Postgres

I'm having trouble with the error message in the title when trying to retrieve all users in my express .get('/users') method. I am using Node.js, Express, and node-postgres. I have my
getUsers(); function defined in my queries.js file, and I call the function in my app.get() function in my index.js file.
queries.js
const client = require('./object models/db_client_pool')
const Pool = require('pg').Pool
const pool = new Pool(client.client)
async function getUsers(request, response) {
await pool.connect()
pool.query('select * from discord_users', (error, results) => {
if (error) {
throw error
}
response.sendStatus(200).json(results.rows)
pool.release();
})
}
module.exports = {
getUsers
}
index.js
const express = require('express');
require('dotenv').config();
//const bodyParser = require('body-parser'); deprecated
const app = express();
const port = 3000;
const db = require('./queries');
app.use(express.json())
app.use(express.urlencoded({
extended: true
}))
app.get('/', (request, response) => {
response.json({ info: 'Node.js, Express, and Postgres API' })
})
app.get('/users', (req, res) => {
db.getUsers(req, res)
})
app.listen(port, () => {
console.log(`App is listening on port ${port}`);
});
As I said, I keep getting the "cannot set headers after they are sent to the client" error and I'm at a loss of what to do. Thanks in advance for your help!
Change from this:
response.sendStatus(200).json(results.rows)
to this:
response.status(200).json(results.rows);
or even just to this:
response.json(result.rows); // 200 is the default status already
The last one is fine because 200 is already the default status so you don't need to set that yourself.
The problem is that response.sendStatus(200) sends a complete response with an empty body and then you try to call response.json(result.rows) which tries to send ANOTHER response to the same request. Trying to send that second response to the same request is what triggers the error message you are getting.
response.status(200) just sets the status to 200 as a property on the waiting response object and waits for some other method to actually send the response itself which you can then do with .json(...).
So my guess is, you're running express 4.x and that doesn't support response.sendStatus(200) anymore. You have to use response.status(200) instead.
Now, another issue I see in your code is, I don't recognize pool.release() method from pg library. You can release a client back to a pool but you can't release a pool of clients. Maybe you meant pool.end()?

Retrieve particular values from the POST endpoint in Express

I have an API definition /task/{activityId}?status={status} ( method = POST)
Input -> activityId, status
Output -> status
In Express I have written my code like this for debugging purpose -
const express = require("express");
const app = express();
const cors = require("cors");
const pool = require("./db");
const axios = require('axios');
app.use(cors());
app.use(express.json());
app.post("/task/:activityId?status=:status", async (req, res) => {
try {
var activityId = req.params.activityId;
var status = req.params.status;
console.log(status);
console.log(activityId);
if (status == "COMPLETE")
const updateStatus = await pool.query("update public.\"TableOne\" set \"Status\"='COMPLETE' where \"ActivityId\"='" + activityId + "'");
}
catch (err) {
console.error(err.message);
}
})
app.listen(5000, () => {
console.log("server has started on port 5000");
})
I am not able to see the values in console of activity id and status passed when I am hitting the endpoint from postman with something like this -
[POST] http://hostname:port/task/A1?status=PENDING
What mistake am I making here?
In order to get values from parameter, proper way is like this
console.log(req.params.status);
But secondary parameter named status is stated as querystring parameter, So, you need to fetch like this,
console.log(req.query.status);
Also, you don’t need to mention status in the code, so, your code to fetch the param should be like this:
app.post("/task/:activityId", async (req, res) => {
As you can see, I didn’t mention the status parameter. Still I will get it.

Not getting expected results from included files in Nodejs

I'm not getting expected results by including files in Nodejs. Here is my code:
Service Route File
const express = require('express');
const router = express.Router();
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Main Server File
const express = require('express');
const userApiService = require('./routes/userService');
const userAdminService = require('./routes/userService');
app.use('/api/user_service/', userApiService("/api", config.userServiceUrl) );
app.use('/admin/user_service/', userAdminService("/admin", config.userServiceUrl) );
var server = app.listen(3000, function(){
console.log('Server listening on port 3000');
});
module.exports = server;
Expecting Console Result:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /admin (when hitting http://baseurl.com/admin/<anything>)
But Getting Console Output as:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /api (when hitting http://baseurl.com/admin/<anything>)
Both the time, returning /api path.
Can anyone tell me why is it happening and what's the solution?
You're creating only one router in userService.js (the first file). It's created once before the function so you really only end up with one router. The first time you require it the router gets created, but the second time you require it Node knows it was already loaded and it's not re-initialized. You should be creating a different router for each case like this:
const express = require('express');
// const router = express.Router(); <-- don't do it here
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
const router = express.Router(); // <--- create a new router for each case
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Also in your main server file you only need to require it once. It's just a function to create the service so you don't need 2 different variables holding that function. So you can initialize both using the one function like this:
// const userApiService = require('./routes/userService');
// const userAdminService = require('./routes/userService');
const service = require('./routes/userService');
app.use('/api/user_service/', service("/api", config.userServiceUrl) );
app.use('/admin/user_service/', service("/admin", config.userServiceUrl) );

Stripe Firebase Cloud Functions - res.send() is not a function

I'm new to server development and trying to get my cloud firebase function working. I'm getting a res.send() is not a function on my firebase Log when my stripe webhook fires and I'm not too sure why. I'm pretty sure I'm missing something. The only conclusion I can come up with is that it is because I'm not using App from const app = express(); but I'm seeing it used elsewhere.
Any and all help/direction is appreciated
I'm getting the following:
res.send() is not a function
res.end() is not a function
res.json() is not a function
Anything that is dealing with res seems to be an issue.
Here is my code:
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
const Chatkit = require('#pusher/chatkit-server');
const stripeToken = require('stripe')(functions.config().stripe.token);
const stripeWebhooks = require('stripe')(functions.config().keys.webhooks);
const express = require('express');
const cors = require('cors');
const endpointSecret = functions.config().keys.signing;
const request = require('request-promise');
const app = express();
app.use(cors({ origin: true }));
exports.stripeCreateOathResponseToken = functions.https.onRequest(cors((req, res) => {
const endpointSecret = "whsec_XXXXXXXXXXXXXXXXXXX";
// Get the signature from the request header
let sig = req.headers["stripe-signature"];
let rawbody = req.rawBody;
// res.send("testing res.send()"); // doesnt work. cant use res.send() here
console.log("rawbody: " + rawbody);
console.log("request.body: " + req.body);
console.log("request.query.code: " + req.query.code);
console.log("request.query.body: " + req.query.body);
console.log("request.query.state: " + req.query.state);
// console.log("res.body: " + res.json({received: true}));
stripeWebhooks.webhooks.constructEvent(req.rawBody, sig, endpointSecret);
res.end("testing res.end()"); // doesnt work. cant use res.end() here
}));
That doesn't look like the correct way to use the cors module with Cloud Functions for Firebase. Try this instead:
exports.stripeCreateOathResponseToken =
functions.https.onRequest((req, res) => {
return cors(req, res, () => {
// put your function code here
});
});
Cribbed from an official sample.

How to retrieve pdf from remote server and return it as a koa response?

I have a node app using koa, and trying to retrieve remote pdf, and return it as a response of my koa request. Here is the code:
router.get('/pdf', function *() {
const url = 'http://example.com/pdf'
const res = yield request(url)
this.status = res.statusCode
Object.keys(res.headers).forEach(key => {
this.set(key, res.headers[key])
})
this.body = res.body
})
I get the pdf with blank page, but it should have content in it. Does anyone have an idea what could be the solution?
This was a little tricky to figure out. I found out that the stream package's PassThrough function had to be used. The code below streams an external PDF to the /pdf route and it will be openable in a browser.
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
// Source: http://koajs.com/#stream
const PassThrough = require('stream').PassThrough;
const request = require('request');
router.get('/pdf', (ctx) => {
const url = 'https://collegereadiness.collegeboard.org/pdf/sat-practice-test-8.pdf';
ctx.set('Content-Type', 'application/pdf');
ctx.body = request(url).pipe(PassThrough());
});
app
.use(router.routes());
app.listen(3000);

Resources