I am pretty new to node and express.js and I'm new to the concept of REST applications as well. I want to code a typical CRUD app, some sort of diary. Hence, I have a collection of entries, can view a single entry and can add, edit and delete an entry.
I'm not quite getting yet, how URi's have to be set up to represent a REST conform API. I would create something like this in my app.js:
// GET REQUEST ROUTING
app.get('/', diary_router.home);
app.get('/entries/', diary_router.listEntries);
app.get('/entries/:id', diary_router.getSingleEntry);
// POST REQUEST ROUTING
app.post('/entries/', diary_router.addEntry);
// PUT REQUEST ROUTING
app.put('/entries/', diary_router.updateEntry);
// DELETE REQUEST ROUTING
app.delete('/entries/', diary_router.deleteEntry);
Could that be called a REST conform interface? Should I rather add the respective action in the routes, such as this and does the item-ID need to be shown in the URL for PUT and DELETE actions, too?:
// GET REQUEST ROUTING
app.get('/', diary_router.home);
app.get('/entries/', diary_router.listEntries);
app.get('/entries/show/:id', diary_router.getSingleEntry);
// POST REQUEST ROUTING
app.post('/entries/add/', diary_router.addEntry);
// PUT REQUEST ROUTING
app.put('/entries/update/:id', diary_router.updateEntry);
// DELETE REQUEST ROUTING
app.delete('/entries/delete/:id', diary_router.deleteEntry);
What would be best practice here? Any help is much appreciated.
B.
In the loose definition of REST that we seem to have converged on in web-land, the first option seems to fit best.
Edit: and yes, you should specify the ID in the PUT and DELETE routes.
HTTP is a really cool protocol for applying verbs (request methods) to nouns (URLs). In that spirit, it's probably best to use the request method to differentiate what you want to do to the resource that you're requesting.
Note: you can use the methodOverride middleware in express if you're worried about browsers not being able to use arbitrary HTTP methods.
The way the methodOverride middleware works is that you use an <input type="hidden" name="_method" value="PUT"> or similar to specify the method, despite it just being a regular POST request, and the methodOverride middleware will set the method property on the request that you get in your express application. This way, you can signal the intended request method without the client actually having to support that method.
Related
(i know there are a few official tools for SSR but we decided to roll our own for various reasons that are not important for this question)
We have a prototype of a server-side renderer running in nodejs for vue with Puppeteer. It works very well and now I would like to cache routes we want to cache. The cache invalidation is simple.
We intend to use Redis to hold the cache objects.
Proposed flow of the server:
Incoming request hits the express app
An express request middleware 1st checks if the route should be cached, if not return index.html. END else continue.
The same middleware checks if there is a Redis cache object based on incoming request object data, if yes return cache & END else continue.
Express router matches the request to a route, passes the request to the respective domain layer, creates the cache then returns it. END else next.
No express route found, handle 404 & END.
The question I have relates to proposed flow step 2
To know if the request should be cached is based on 2 parameters:
does the request cookie contain a valid token
is the request path one which is also defined in the express routes
The express routes currently look as follows, but is liable to evolve:
GET /channel/:name
GET /channel/:name/:tag
GET /item/:id
So, how in step 2 can we check if the incoming route is a route that would match the express router?
As said in first comment, express already provde a way to do this :
app.get('/channel/:name/:tag', YOUR_MIDDLEWARE, (req, res) => {
// Your Handler
})
I am overall clueless about how and why you set up a node.js app, and how any of the app.use functions work - the tutorials on it don't explain the why of anything.
Anyway, I have socket.io, res.locals and index.js set up like so in the app.js root file.
const sockets = require('./models/socket')(io)
app.use(function (req, res, next) {
res.locals.user_id = req.session.user_id;
next();
});
const routes = require('./routes/index');
app.use('/', routes);
I'd like to be able to access res.locals in the socket.js model, like I can in index.js found in the routes folder.
I can't guess how to go about doing this. If anybody is able to explain how and why I can or can't that would be a bonus. Thanks!
Welcome to Expressjs, there are a few fundamentals you should probably research before going any further, they'll help solve some of your confusion. I'll give a brief explanation of them but I suggest you do further research. I'll then answer your actual question at the end.
Middleware and app.use
Expressjs is built upon an idea that everything is just "middleware". Middleware is a function which runs as part of a request chain. A request chain is essentially a single client request, which then goes through a chain of a number of middleware functions until it either reaches the end of the chain, exits early by returning a response to the client, or errors.
Express middleware is a function which takes the following three arguments.
req (request) - Representing the request made by a client to your
server.
res (response) - Representing the response you will return to
the client.
next - A way of telling express that your current
middleware function is done, and it should now call the next piece of
middleware. This can either be called "empty" as next(); or with an
error next(new Error());. If it is called empty, it will trigger
the next piece of middleware, if it is called with an error then it
will call the first piece of error middleware. If next is not called at the
end of a piece of middleware, then the request is deemed finished and the
response object is sent to the user.
app.use is a way of setting middleware, this means it will run for every request (unless next() is either not called by the previous piece of middleware for some reason, or it's called with an error). This middleware will run for any HTTP request type (GET, POST, PUT, DELETE, etc).
app.use can take multiple arguments, the important ones for beginners to learn are: app.use(func) and app.use(path, func). The former sets "global" middleware which runs no matter what endpoint (url path) the client requests, the latter (with a specific path) is run only if that specific path is hit. I.e. app.use('/hello', (req, res, next) => { res.send('world'); }); will return "world" when the endpoint "/hello" is hit, but not if the client requests "/hi". Where as app.use((req, res, next) => { res.send('world'); }); would return "world" when you hit any endpoint.
There are more complex things you can do with this, but that's the basics of attaching middleware to your application. The order they are attached to the application, is the order in which they will run.
One more thing, this will blow your mind, an express application made with the standard const app = express() can also be used as middleware. This means you can create several express applications, and then mount them using app.use to a single express application. This is pretty advanced, but does allow you to do some really great things with Express.
Why can you not access res.locals in socket.io? (The real question)
Within your middleware handler, you are setting up a res.locals.use_id property. This only lives with that individual request, you can pass it around as long as the request is alive by passing it into other functions, but outside of that request it doesn't exist. res is literally the response object that tells Express how to respond to the clients request, you can set properties of it during the request but once that HTTP request has ended it's gone.
Socket.io is a way of handling web socket requests, not standard HTTP requests. Thus, in a standard express HTTP request you will not be able to hand off the connection to anything with socket.io, because the connection is a single short lived HTTP request. Likewise, you won't be able to do the same the other way.
If you wish to find the users id in a socket.io request, you'll have to do this within the socket.io request itself.
Right now, you're entering a piece of middleware for an Express.js request, you are then calling next() which runs the next piece of express middleware, at no point does it cross over into Socket.io realms. This is often confused by tutorials because Socket.io can handle requests across the same port as Express is listening on, but the two are not crossed over. So you will need to write separate middleware for both Express.js requests chains, and socket.io request chains. There are ways of writing this code once and then writing an adapter to use it across both platforms, but that's not what you've tried to do here.
I would suggest you look at doing just nodejs and express for a time before taking on socket.io as well, otherwise you're trying to learn a whole heap of technologies all at once is quite a lot to try and take on board all at once.
I am building a web api with Express and have not found information on accessing incoming custom request headers.
I will be expecting, for instance, that an incoming post request have a provider_identifier header. When I receive the request, I need to access that header information to validate their subscription.
Can someone point me in the right direction/provide advice on this?
router.post('myendpoint/', function(req, res){
var providerId = req.????;
});
Answering my own question here... was kindof a DUH moment for me.
Using above example, simply reference the headers collection like so:
var providerId = req.headers.provider_identifier;
One note: Use an underscore rather than a dash. "provider-identifier" doesn't work, but "provider_identifier" does.
I'm using Express 4.x, and I'm trying to customize the automatically generated OPTIONS response, without having to re-implement all of the functionality that express is already providing for free.
So, for example, if I have PUT and POST handlers registered on /foo, making an OPTIONS call to /foo will return an Allow header with PUT,POST, and a body with the same value. What I am trying to do is to just customize this response. So where express normally returns a body with
PUT,POST
I would like to return something like
{"methods":["PUT","POST"]}
Is there any way to do this without fully re-implementing everything express is doing behind the scenes?
The solution I found was to handle options explicitly on each route, and pull the allowed methods from req.route.methods.
app
.route('/foo')
.post(...)
.put(...)
.options(funtion(req, res, next){
var allowMethods = req.route.methods;
});
I am new to node.js and express and have been experimenting with them for a while. Now I am confused with the design of the express framework related to parsing the request body.
From the official guide of express:
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
After setting up all the middleware, then we add the route that we want to handle:
app.post('/test', function(req, res){
//do something with req.body
});
The problem with this approach is that all request body will be parsed first before the route validity is checked. It seems very inefficient to parse the body of invalid requests. And even more, if we enable the upload processing:
app.use(express.bodyParser({uploadDir: '/temp_dir'}));
Any client can bombard the server by uploading any files (by sending request to ANY route/path!!), all which will be processed and kept in the '/temp_dir'. I can't believe that this default method is being widely promoted!
We can of course use the bodyParser function when defining the route:
app.post('/test1', bodyParser, routeHandler1);
app.post('/test2', bodyParser, routeHandler2);
or even perhaps parse the body in each function that handle the route. However, this is tedious to do.
Is there any better way to use express.bodyParser for all valid (defined) routes only, and to use the file upload handling capability only on selected routes, without having a lot of code repetitions?
Your second method is fine. Remember you can also pass arrays of middleware functions to app.post, app.get and friends. So you can define an array called uploadMiddleware with your things that handle POST bodies, uploads, etc, and use that.
app.post('/test1', uploadMiddleware, routeHandler1);
The examples are for beginners. Beginner code to help you get the damn thing working on day 1 and production code that is efficient and secure are often very different. You make a certainly valid point about not accepting uploads to arbitrary paths. As to parsing all request bodies being 'very inefficient', that depends on the ratio of invalid/attack POST requests to legitimate requests that are sent to your application. The average background radiation of attack probe requests is probably not enough to worry about until your site starts to get popular.
Also here's a blog post with further details of the security considerations of bodyParser.