I'm in express 4.16.3.
At first, this code works fine:
const express = require('express')
const router = express.Router()
let app = express()
router.use((req, res, next) => {
console.log('hi, express')
next()
})
app.use(router)
app.all('*', (req, res) => {
res.send("hello, world")
})
app.listen(8075, function () {
console.log('listening localhost:8072')
})
But when I try to set a param in next():
const express = require('express')
const router = express.Router()
let app = express()
router.use((req, res, next) => {
next('hello, express') ----------------mark
})
app.use(router)
app.all('*', (msg, req, res) => {
console.log(msg)
res.send(msg)
})
app.listen(8075, function () {
console.log('listening localhost:8072')
})
the response is always an error page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>hello, express</pre>
</body>
</html>
I just add a param in next function, but it seems broken express router.
What is the right way to use next() with params?
Isn't it a better practice to attach your required data with req object before calling next() ?
router.use((req, res, next) => {
req.data = { title: 'your sample data' };
next();
});
app.all('*', (req, res) => {
console.log(req.data);
});
This will attach your required data with the request object and pass the control to the next processing pipeline(app.all() handler in your code).
Then you can use that object in all of the available routes.
I don't know where in the Express docs this is stated, but what you're calling when you invoke next isn't another middleware function directly, rather telling the Express framework to call the next middleware function. A middleware function has fixed arguments passed to it, so you will only have access to the request, the response, and a function that may call the next middleware function in the chain. The only parameters this function takes is optionally the string 'route'.
In order to pass data to the next middleware function down the line your best bet is to modify the request object or the response object.
See Using Express middleware on the Express website.
Related
As the title says, I simply don't understand what is going on here. Once I include the app.use(bodyParser.json) line, Postman just keeps handing on any request I make. I lost a good portion of the day thinking I messed up my routes.
I narrowed it down to it in this little testing file:
const express = require("express")
const bodyParser = require("body-parser")
const env = require("dotenv");
const app = express()
env.config();
app.use(bodyParser.json);
app.get("/", (req, res) => {
res.status(200).json({
message:"Hello World"
})
});
app.post("/data", (req, res) => {
req.status(200).json({
message: req.body
})
});
app.listen(process.env.PORT, ()=>{
console.log(`Server listening at port ${process.env.PORT}`);
})
Can anyone tell me what is happening and how I can fix it?
You need to call JSON body parser as a function (with brackets):
app.use(bodyParser.json());
There is another bug in the post method "data", You should call status from "res" object:
app.post("/data", (req, res) => {
res.status(200).json({
message: req.body
})
});
I am trying to run router.route() with the following code
const express = require('express');
const app = express();
const router = express.Router();
router.route('/test').get(function (req, res, next) {
res.send('You have reached localhost:9000/test');
next();
});
app.listen(9000, () => {
console.log('Running on port 9000');
});
But it doesn't seem like anything is happening at all. Regardless of what I do, localhost:9000/test will not return anything Cannot GET /test. I don't understand what I'm doing wrong. Thanks in advance
You have to hook the router into your app with app.use():
const express = require('express');
const app = express();
const router = express.Router();
router.get('/test', function (req, res, next) {
res.send('You have reached localhost:9000/test');
});
app.use(router); // <=== add this
app.listen(9000, () => {
console.log('Running on port 9000');
});
Your original code creates a router object, but that router object is not hooked up to any web server yet. Using app.use(), you can hook it up to your web server so that it actually gets a chance to see the incoming requests.
Also, do not call next() after you call res.send(). Pick one of the other. Once you send a response, you do not want to continue routing to other routes because that will often try to then send another response, but you can only send one response to a given incoming http request.
You can simply use the Router().get(...) function instead.
The <Router>.get('/path', function() {...}); function will listen for incoming traffic to the path /path and then fire the callback function with the parameters request, response and next.
Example:
router.get('/test', function (req, res) {
res.send('You have reached localhost:9000/test');
});
Full example:
const express = require('express');
const app = express();
const router = express.Router();
router.get('/test', function (req, res) {
res.send('You have reached localhost:9000/test');
});
app.listen(9000, () => {
console.log('Running on port 9000');
});
Note: Using the next() function after sending a response to an incoming HTTP request will result in an error.
With express we can use different middlewares for get and post requests,
eg.
// GET method route
app.get('/users', function (req, res) {
// handle get request
})
// POST method route
app.post('/users', auth, function (req, res) {
// handle post request
})
How do I do the same in next js.
I am totally new to next js. I might be simply missing something.
To handle different HTTP methods in an API route, you can use req.method in your request handler.
export default function handler(req, res) {
if (req.method === 'POST') {
// Process a POST request
} else {
// Handle any other HTTP method
}
}
Or you can use a package like next-connect which enables expressjs like API.
In your api file:
import nc from "next-connect";
const handler = nc()
.use(someMiddleware())
.get((req, res) => {
res.send("Hello world");
})
.post((req, res) => {
res.json({ hello: "world" });
})
.put(async (req, res) => {
res.end("async/await is also supported!");
})
.patch(async (req, res) => {
throw new Error("Throws me around! Error can be caught and handled.");
});
export default handler
Sorry if I posted this incorretly, it is my first question on Stack Overflow. I am currently trying to use express to serve third party API requests to my React front-end. This is because the steam api I use throws me a CORS error when requesting in the client-side. I tried to route the requests to my controller which makes the axios call, but I have had no luck. Not sure if I am doing something completely incorrect.
here is my server.js
const app = require('./app.js');
const PORT = process.env.PORT || 3005;
app.listen(PORT, () => console.log(`Listening on port: ${PORT}`))
and here is my app.js
const express = require('express');
const cors = require('cors')
const app = express();
app.use(cors())
module.exports = app
my routes:
const { Router } = require('express')
const controllers = require('../controllers')
const router = Router()
router.get('/', (req, res) => res.send('This is root!'))
router.get('/applist', controllers.getAllSteamGames)
router.get('/game/:id', controllers.getSingleGameSteam )
router.get('/gameSpy/:id', controllers.getSingleGameSpy)
module.exports = router
and lastly my controller:
const axios = require('axios');
const getAllSteamGames = async () => {
try {
const resp = await axios.get('https://api.steampowered.com/ISteamApps/GetAppList/v2?applist')
return resp.data
} catch (error) {
console.log(error)
throw error
}
}
Thank you for your help and time.
You aren't doing anything to send a response back to the client. If we look at the /applist route:
router.get('/applist', controllers.getAllSteamGames)
const axios = require('axios');
const getAllSteamGames = async () => {
try {
const resp = await axios.get('https://api.steampowered.com/ISteamApps/GetAppList/v2?applist');
return resp.data
} catch (error) {
console.log(error)
throw error
}
}
All, your getAllSteamGames() function does is return a promise that resolves to a value (remember all async functions return a promise). It doesn't send a response back to the client.
Then, if you look at the actual route handler, it doesn't send a response back to the client either. So, you get the request and never send a response. The client never gets a response.
What I would suggest is that you just send a response in your controller. It's already passed (req, res) as arguments to the function so you can use them.
router.get('/applist', controllers.getAllSteamGames)
const axios = require('axios');
const getAllSteamGames = async (req, res) => {
try {
const resp = await axios.get('https://api.steampowered.com/ISteamApps/GetAppList/v2?applist');
res.json(resp.data);
} catch (error) {
// send error status upon error
console.log(error);
res.sendStatus(500);
}
}
I need to send custom error message in JSON format, from my express app, served in a lambda function using serverless-http
Please correct me if i got it wrong, but as i understand it, we need to use LAMBA_PROXY APIG integration to be able to send custom error messages defined directly from a lambda function.
This is what i have tried so far:
res.status(400).json({ message: 'email already taken' });
serverless.yml
functions:
auth:
handler: src/express/auth/index.handler
name: ${self:service}-auth-${env:STAGE}
# warmup: true
integration: lambda-proxy
memorySize: 128
timeout: 15
events:
- http:
path: /auth/
method: ANY
cors: true
- http:
path: /auth/{any+}
method: ANY
cors: true
this is what the API is returning(with status code 400)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Bad Request</pre>
</body>
</html>
Any leads, on how I can send a custom response, in JSON format?
update:
After more tests, I found out that calling next(error) doesn't reach the last error handler
const register = async (req, res, next) {
try {
await verifyEmail(req.body.email);
const user = await Users.register(req.body);
const token = sign(user.attrs, {});
res.json({ token, user });
} catch (e) {
next(e);
}
};
const generalError = async (err, req, res, next) => {
// doesn't reach this part! :(
console.log('generalError handler', JSON.stringify(err));
res.status(errorOut.status).json(errorOut);
};
ApiRouter.post('/register', register);
app.use('/auth', ApiRouter);
app.use(generalError);
(I just answered a very similar question here)
Yes, this is explained in the Express docs under Error Handling.
Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.
If you pass an error to next() and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
To override this handler, refer to the section in the Express docs titled Writing error handlers.
It explains:
Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next). For example:
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
You define error-handling middleware last, after other app.use() and routes calls
So in your case, if you wanted to respond with a 400 and some JSON, you might write something like this:
const serverless = require('serverless-http');
const express = require('express');
const app = express();
// Your middleware and other routes here
app.use(/* register your middleware as normal */);
// Finally, your custom error handler
app.use(function customErrorHandler(err, req, res, next) {
res.status(400).json({ message: 'email already taken' });
});
module.exports.handler = serverless(app);