API Gateway example for node.js - node.js

Looking for a good example of how to implement a node API gateway for a microservice application, I understand the purpose of having a gateway, I am just not sure of how to implement this without just adding another level of RESTful route calls. To me a gateway is supposed to just direct the route to the microservice.
API Gateway port 3000
router.use('/microservicename/*', function (req, res, next) {
**code that will direct to microservice**
});
Microservice1 server.js port 3001
var express = require('express');
var app = express();
var routes = require('./routes/routes');
app.use('/microservicename', routes);
var server = app.listen(3001, function () {
console.log('Server running at http://127.0.0.1:3001/');
});
Microservice1 router.js (3001)
router.get('/route1', function (req, res, next) {
//get route code
});
router.post('/route2', function (req, res, next) {
//post route code
});
router.put('/route3', function (req, res, next) {
//put route code
});
router.delete('/route4', function (req, res, next) {
//delete route code
});

Assuming your microservice is its own http server (if not, then please explain more about its architecture) and assuming your API is designed such that you can easily identify which routes go to which microservice without specifying every single possible route, then you should be able to create one route handler for an entire microservice (or at worst a very small number of route handlers for the entire microservice).
For example, if all requests that start with /api/foo go to the foo microservice, then you should be able to have a single route handler that catches /api/foo/* and proxies that to the microservice. If you have common middleware for all requests (such as middleware that runs or verifies an authentication process), that can be in the stack before the proxy route handlers so it will be invoked for all requests that go to the microservice.
If you don't have a 1-to-1 mapping between incoming API calls and microservice APIs, then you have to create a mapping between the two. Depending upon the level of mismatch, you may be able to do this with a table-driven approach where you specify what matches with what in a table and then one piece of generic code processes all the definitions in the table.

Related

Express routes invoking multiple router function

I've created a NodeJS Express app. But my express route is invocking multiple routes function, one after another, but I only need one at a time.
My express app.js
app.use(routes)
Express router:
const router = express.Router();
router.post("/product", controller.productFunction)
router.post("/user", controller.userFunction)
router.get("/:id", idController.getId)
Whenever I create a post request for "/product" route, first the productFunction is invocked, but then the "/:id" routes getId function is also get invocked. Same thing happen for /user route as well. Always /:id route is getting invocked.
Is there any way to prevent this?
I even tried this way, but after the homepage loading then again it invockes getId function.
app.get("/", (req, res, next) => {
res.sendFile(..........);
});
app.use(routes);
I am sure that this is not an issue with the router itself.
You can't skip from POST to GET handling. So invocations are caused by different requests.
router.get("/:id", idController.getId) kind of wild card, and <server_url>/favicon.ico will trigger it
If you check it via browser it tries to get favicon or smth else and invokes this handler.
Try to make POST request via curl/Postman and idController.getId should not be called.
It is risky to serve static and process requests on a same level.
You can add some prefix to all your request, like that app.use('/api', routes); then static file will be available on /<file_name> and all server logic will be under /api/<request>

Express framework - Is a route's execution always completed before execution can begin on a new route regardless of async?

I have a basic, mechanical question on the Node.js Express framework.
When a client hits an endpoint a route is executed. For example,
app.get('/' function(req, res, next) {
res.send('hello world');
}
If a second client hits an endpoint during the execution of this route does Express instruct the second route to wait until the first route is completely finished?
What if the route contains asynchronous code. For example,
app.get('/' function(req, res, next) {
// async function below
bcrypt.compare(password, hash)
.then()
.catch();
}
Since bcrypt.compare() is asynchronous will Express begin executing the second client's route before the first client's route is completely finished? Or alternately does Express run one route at a time regardless of async?

NodeJs/Express: Authorise all endpoints except one

In my NodeJs/express based application, I am authorizing calls to all the endpoints by using the following middleware.
app.use(restrictByCookieMiddleware);
I want to authorize all endpoints except one i.e. I don't want "restrictByCookieMiddleware" middleware to run for "/metrics" endpoint. Is there a way to escape one endpoint?
Here, I found some examples that matches endpoint for which middleware should run, I am looking for a solution that skips one.
Your have a couple of choices:
First, you can just define the one exception route handler BEFORE the middleware. Then, it will handle that route and the routing will never get to the middleware.
app.get("/login", (req, res) => {
// handle that one special route here
});
// all other routes will get this middleware
app.use(restrictByCookieMiddleware);
Second, you can make a wrapper for the middleware that compares to the one specific route and skips the middleware if it's that route:
app.use((req, res, next) => {
// shortcircuit the /login path so it doesn't call the middleware
if (req.path === "/login") {
next();
} else {
restrictByCookieMiddleware(req, res, next);
}
});
// then, somewhere else in your code would be the /login route
app.get("/login", ...);
Third, if you have multiple routes that you want to skip the middleware for, you can segment things by router. Create a router for the non-middleware routes and put all of them on that router. Hook that router into the app object first.
Then, create a second router that contains the middleware and has all your other routes on it.
Place that specific route, you want to exclude, before this line:
app.use(restrictByCookieMiddleware);
So this will solve your problem.

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.

Nodejs - Hosting to subroute

I want to host my nodejs server application in a sub route in iis. What i want to do is host my application as such localhost:3000/node/ not localhost:3000/.
This can be achieved by
changing endpoints from
app.get('/', moduleRoutes.root);
app.post('/auth/signup/', authenticationRoutes.signup);
to
app.get('/node/', moduleRoutes.root);
app.post('/node/auth/signup/', authenticationRoutes.signup);
but i don't want to change all the api endpoint every time I change my hosting path.
another is
app.use((req, res, next) => {
//change request location from here by changing
req.url = req.url.replace('localhost:3000/node/', 'localhost:3000')
//somthing like that
authorization.memberinfo(req, res, next);
});
but this does not look like a proper way to achieve this. Please direct me toward the right direction. Thanks.
You could just mount a router at /node and just add all of your routes to that router instead:
// These three lines could even be placed in a separate file that you
// would `require()` and use in your app.js
var router = express.Router();
router.get('/', moduleRoutes.root);
router.post('/auth/signup/', authenticationRoutes.signup);
app.use('/node', router);

Resources