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.
Related
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()?
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));
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.
I'm running a standard NodeJs 8 with Express and currently when a request for an existing path but un-supported method comes in, Express return 404.
For example 'POST /login' is supported, but 'GET /login' is not, but it returns 404.
How can I make Express return 405 in such a case?
Here's the routes file:
const express = require('express');
const router = express.Router();
const loginController = require('../controllers/login');
router.route('/login').post(loginController.loginUser);
module.exports = router;
Please advise.
You can simply add the .all() handler to your route chain, like so:
const methodNotAllowed = (req, res, next) => res.status(405).send();
router
.route(`/login`)
.post(loginController.loginUser)
.all(methodNotAllowed);
Explanation
This works because requests are passed to the handlers in the order they are attached to the route (the request "waterfall"). The .post() handler will catch your POST requests, and the rest will fall through to the .all() handler.
Also see this question for more details.
Authenticating all POST routes
If you would like to ensure that the user is logged in for all POST requests, but return a 405 response for any other requests, you can use a regular expression to match all routes with router.post('*'), like so:
router
.post(`*`, loginController.loginUser)
.all(methodNotAllowed);
The problem with this approach, however, is that no 404 errors will ever be returned to the client, only 405. Therefore I recommend attaching the methodNotAllowed handler to each individual route, like in the first code snippet above. This approach will return 404 errors for routes that don't exist, but 405 errors for routes that do.
Determining the available methods for a route
To determine which methods are allowed for a route, use router.stack:
app.use((req, res, next) => {
const methods = router.stack
// Filter for the route that matches the currently matched route
.filter(layer => layer.route.path === req.path)[0]
.route
.methods;
if (!methods[req.method]) methodNotAllowed(req, res, next);
else next();
});
You can try this that way:
app.route("/login")
.get((req, res) => {
/* HANDLE GET */
})
.post((req, res) => {
/* HANDLE POST */
})
.all((req, res) => {
res.status(405).send();
});
How it works?
If request matches the route. It will go through the handlers. If a handler is present, it will be handled using that specific one. Otherwise, it will reach the 'all' handler that will set the status code to 405 and send the response.
Here You can find the discussion about it:
405 issue
#You question below:
You can try that way:
loginRoutes.js content:
const router = require('express').Router();
router.route('/')
.get((req, res) => {
res.status(200).send()
})
module.exports = router
server file content:
const express = require('express')
const app = express();
const router = express.Router();
const loginRoutes = require('./loginRoutes')
const PORT = process.env.PORT || 8080;
router.use('/login', loginRoutes)
router.route('/login').all((req, res) => { res.status(405).send() })
app.use(router);
app.listen(PORT, () => console.log(`started on port: ${PORT}`))
You can use this snippet of code to automatically send 405 status code when route from the same path exist but not with the current method
app.use(function (req, res, next) {
const AllLayers = app._router.stack
const Layers = AllLayers.filter(x => x.name === 'bound dispatch' && x.regexp.test(req.path))
const Methods = [];
Layers.forEach(layer => {
for (let method in layer.route.methods) {
if (layer.route.methods[method] === true) {
Methods.push(method.toUpperCase());
}
}
})
if (Layers.length !== 0 && !Methods.includes(req.method)) {
res.setHeader('Allow', Methods.join(','))
if (req.method === "OPTIONS") {
return res.send(Methods.join(', '))
}
else {
return res.sendStatus(405);
}
}
else {
next();
}
});
Hope this could be helpfull to someone
If you want to determine what methods COULD have been used you need to do a lot of digging in the app function you start your server with, and through some string manipulation and the like you can figure out what the possible methods are and return them in the error. If you're interested in how its done check out https://github.com/Justinlkirk/express-ez-405 or just use the npm package here https://www.npmjs.com/package/express-ez-405
I want to call a function using the parameters passed to an express call. Here's an example tying to do a simple console.log inside a function called inside the app.get():
// server.js
const express = require('express')
const app = express()
const port = process.env.PORT || 3001
function processRequest(api_key, another_value) {
console.log(api_key, another_value)
}
app.get('/api', function(req, res) {
let api_key = req.query.api_key
let another_value = req.query.another_value
processRequest(api_key, another_value)
res.json({api_key, another_value})
})
app.listen(port)
console.log("Started server")
and a simple test
const axios = require('axios')
function test() {
axios.get('localhost:3001/api?api_key=testkey&another_value=anothervalue', res => console.log(res.data))
}
test()
I know i'm missing something simple here.
Thanks ya'll
Use req.query.somevalue to get query params from request.
req.param only works for URL params like api/distance/:id
Some from docs:
(req.params) Checks route params, ex: /user/:id
(req.query) Checks query string params, ex: ?id=12 Checks urlencoded body params