Nodejs express: how to use common function needed by different routes logic - node.js

How can I add common methods/functions that can be used by different routes built using express in nodejs?
I created a nodejs server that is currently serving 3 APIs. For example:
/cars
/cars/:id
/cars/:id/sellers
All these 3 APIs retrieves data from another external APIs. So, I already have some code that is similar in all of those routes. For example, sending a GET request to the external API endpoint but with different parameters.
For the last API in my list above, I want to enhance it so that it will take optional paramters (lastname, firstname). I could have another API endpoint like this:
/cars/:id/sellers/:lastname&:firstname
But in this case the logic for this and the 3rd API in my list will be almost identical.
I'd like to create some util functions that I can call from any of my API routes with different parameters. I'm not quite sure to do this or where to begin.
Any suggestions?

app.use((req, res, next) => {
//req.someParam
//your logic
next();
});
You can use a middleware like this make sure to add it after your routes has defined, it will work as a common middleware in the routes
router.post('/cars', (req, res, next) => {
// if() some condition
req.someParam = "param";
next();
});

Related

Whats the difference between a Controller and a Middleware

I am writing and API in express.js. the original API I wrote only utilized routes and raw SQL queries. I have since rewritten the API for the most part NOW using an ORM to react models and migrations.
My question what is the difference and use cases for middleware and controllers. currently only using middleware because most sources online online only explain what a middleware is.
I don't understand the use case of a controller. and I don't want to omit it from my API if its used in proper programming conventions
You should see middleware as a step in your API and controllers as the entity that will actually respond to the requests.
Bellow is an example where authenticationMiddleware is a middleware because it is a step during the processing but should not return the response. It can though, in case of error.
Then getItems actually handle the logic specific to this calls.
As a rule of thumb, middleware are often reused more than once and often they do not response. On contrary, controller respond and are most of the time specific to one endpoint.
const express = require("express");
const app = express();
function authenticationMiddleware(req, res, next) {
// Check that the user is authenticated using req.headers.Authorization
// for example
if (authenticated) {
// The user is authenticated, we can go to the next step
next();
} else {
// The user is not authenticated, we stop here
res.status(401);
res.send("Error during authentication");
}
}
function getItems(req, res, next) {
// Here we focus on the actual response, we assume that the user is authenticated
res.send({ items: [] });
}
app.get("/items", authenticationMiddleware, getItems);
app.post("/items", authenticationMiddleware, createItems); // Re-use the same middleware
app.listen(3000);
If you're referring to the node/express terminology, middleware are simply the callbacks used by the routing functions/methods (get, set, delete, use, etc). Callbacks can either send or not send responses back to the client. The callbacks are really the 'controllers' if you'd like to call them that (eg: ASP.NET Core MVC) but that's up to you. Below is a quote from Express. Note the term 'middleware' and where there's no mention of a 'controller'.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware
function in the application’s request-response cycle. The next
middleware function is commonly denoted by a variable named next.
Middleware functions can perform the following tasks:
Execute any code.
Make changes to the request and the response objects.
End the request-response cycle.
Call the next middleware function in the stack.
'Express' also defines different types of middleware which is useful:
Application-level middleware
Router-level middleware
Error-handling middleware
Built-in middleware Third-party middleware
Here's another nice look at it from Mozilla's pov that does mention a few controller/callback examples.
Beyond that, you can define what a 'controller' is within your team and the naming convention follows from there. Key is your SOLID profile and how you separate your concerns.

Express JS match route without handling

Given an instance of a Express JS app or router, is it possible to match a request against the apps configured routes and receive a object that describes the route as registered with the app?
For instance, if a request for /users/1 were to be handled by the application, would it be possible for the app/router instance to programatically check if the app has a route that would satisfy this request given the URI and HTTP method?
Desirable sudo(ish) code:
const app = express();
app.use((req, res, next) => {
const handler = app.match(req);
// {
// 'method': 'GET',
// 'path': '/user/:id', <--- mainly looking for this
// 'handler': <function reference>
// }
next();
});
app.get('/user/:id', (req, res, next) => {
// fetch the user and do something with it
});
...
AFAIK there are no publicly documented Express router endpoints that provide the behavior you are describing based on its 4.x Documentation.
However, you could implement this yourself by creating a custom regular expression validator to check if the req.path string matches any defined path. The downside to this is that you would have to maintain that list separately from what is registered to Express, which might prove to be difficult to maintain.
You may be able to root through the internals of the app object to get the functionality you need, but note the instability of that approach will mean your solution could potentially be broken by non-major updates to Express.

Node.js cannot view headers inside middleware

I have a Node.js restful API. The problem I am having is that I am not sure why I am not able to see the request headers inside the middleware route.use(), however, it is visible inside get method router.get('/',function(req,res){}).
Can you someone please why is this case or what do I have to do get it visible inside
router.use(function(req,res,next){ next();});
Try something like his
router.use(function (req, res, next) {
console.log(req.headers['header_name']);
if (!req.headers['header_name']) return next('router')
next()
})
To skip the rest of the router’s middleware functions, call next('router') to pass control back out of the router instance.

MEAN: can I register more than a mini router app in app.use()?

In my node/express app.js main file, I have created a mini-app router:
var router = express.Router();
that I am passing inside to my controller functions and exporting again, at the end, I am registering the router in
app.use('/Link', router);
I now wanted to set up a second Controller folder with extra Controller function and routes only for my Angular NGX-Charts, where I prep up my data from mongoDB in correct format. Therefore, I wanted to create a second router object where I am passing and registering the right routes and middleware for that router object.
My question now is, can I create and register more than one router object for my express instance, like app.use('/Link',router1, router2, router3,...) ?
and does it behave the same like one router object then (I mean, will it find the appropriate router according to which routes I am navigating to in my browser and execute the correct middleware)?
Sure, you can do that. Common use-cases would be password-protection, generating auth tokens, parsing payloads, etc.
app.use accepts any number of "middlewares" after the first argument.
Check the docs for more details: https://expressjs.com/en/4x/api.html#app.use
The arguments are fairly flexible, there are a number of options for what you can pass.
A middleware function.
A series of middleware functions (separated by commas).
An array of middleware functions.
A combination of all of the above.
Each function gets 3 arguments, which are the Request, Response, and next callback function. Here's an example with an inline middleware that logs something and forwards to the next handler.
app.use('/secret-stuff', authorize, (req, res, next) => {
console.log('token from auth middleware', req.authToken)
next()
}, render)
One thing to note is that you can only send one response, so only the final handler would send the response to the user. Everything before that should call next() to activate the next middleware in the chain.
You could pass a number of routers as long as you make sure to forward (call next()) when the paths are unmatched. You would need to use some kind of path pattern that would allow for the middleware routers to handle greater specificity in the path (e.g. '/Link/*'), otherwise you wouldn't be able to define any sub-path handlers in the middleware routers.
In the past, I haven't had the need for sub-routers. Middleware works fine for modularization.

Some Connect terminology

Here are three pieces of terminology used in documentation relating to ConnectJS for NodeJS that keeps getting used, but that I don't completely undertand:
1) views and controllers
2) partials and collections
3) Middleware
Let's start from the bottom up.
Level 0: built-in http module
In the beginning, there is node.js's built-in http.Server written by Ryan Dahl. You write a function(req, res), and Node will call your function each time a new connection is accepted:
// Hello world HTTP server using http module:
var http = require('http');
var app = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello, world.');
});
app.listen(8080, '127.0.0.1');
Level 1: Connect
Connect, written by Tim Caswell, is simply a subclass of http.Server that makes it easier to organize your code. Instead of writing a single callback that handles every request, you chain together some middleware. Each middleware is a function(req, res, next) that handles the request if possible, or calls next(error) if it did not finish handling the user's request. The middleware handlers are called in the order of their use; you should call the catch-all app.use(connect.errorHandler()) at the end.
One important middleware is the router, which allows you to filter some middleware based on a pattern of the URL path. The syntax for the route patterns is based on ruby's Sinatra routes. When I use the filter /hello/:name, req.params.name will be set to the matching part of the URL.
var connect = require('connect');
var app = connect.createServer();
app.use(connect.favicon());
app.use(connect.logger());,
app.use(connect.router(function(app) {
app.get('/hello/:name', function(req, res, next) {
try {
if (Math.random() > 0.5) {
throw new Error('Random error!');
}
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello, ' + req.params.name);
} catch (e) {
return next(e);
}
});
}));
app.listen(8080, '127.0.0.1');
In Connect, every handler is middleware! You use whichever functionality you need like bodyParser or cookieParser, and your own business logic is also a middleware function with the same signature function(req, res, next). The connect homepage gives a list of the built-in middleware.
Level 2: Express.js
Express's http server, written by TJ Holowaychuk, is in turn a subclass of Connect that forces the Sinatra style more. In Connect, there was no magic you didn't ask for, but in Express, the router and qs parser (which sets req.query) are automatically used. The router syntax is cleaned up; you call app.get, app.post, etc. directly (and the router is positioned at the first call) rather than putting them inside a function.
Express also contains many other well-documented features and helper functions to extend app, req, and res.
One feature of Express is res.render, which renders the given template file (relative to app.set('views') or $PWD/views) using the template engine implied by the extension, and res.partial, which calls render on each element of a collection (which is just any arraylike object). But I haven't used this optional feature; if you don't care for express's templates you can just res.send data yourself.
Here are some comments. If you have more specific questions, we can try to address them.
1) views and controllers
Views just means a template that can be used to render a response, which is usually HTML but could be plain text or some other format. There are many different templating syntaxes and systems out there. Some work in NodeJS as well as in web browsers. That's all there is to views.
Controllers are the "C" in the MVC design pattern and are responsible as an intermediary between views and models. They are basically the glue that handles some basic things like formatting choices that don't belong in the model code.
2) partials and collections
(Side comment, these are really part of Express.js, not Connect, but they are sibling libraries)
Partials is a document template representing a small portion or snippet of a document, as opposed to a complete HTML document. Partials can be included by other templates and are often re-used by multiple containing templates. Collections go hand in hand with them. For example, you might have a partial to display a "President" object and in that partial you'd have markup for a photo, dates he served as president, political party, etc. You could use that same partial throughout your site whenever you wanted to display a "President" record/object. If you had a collection of several "President" objects, "collections" give you an easy way to say "render a president partial for each president object in this list".
3) middleware
The way connect handles responding to HTTP requests is to route the request through a series of functions called middleware. Each middleware function adheres to a basic API of (req, res, next) and a few behavioral requirements. Each piece of middleware can do one specific bit of processing, then when it's done, call next() to tell connect to move on to the next middleware function in the chain. Connect comes with a bunch of middleware modules which you can see on github. Middleware can do whatever it wants. For example, parse JSON request bodies, search the filesystem for a matching static file to serve, check for session cookies, log to a log file, and so on. This design makes it really easy to re-use code as well as to combine separate middleware functions in novel combinations. Some middleware functions deal with parsing and processing the request, some deal with generating the response. Typically you can find existing middleware functions that do a lot of request processing (parsing, logging, decoding, converting, etc), and you provide your own middleware to actually render the response, which is also usually the last middleware in the chain.

Resources