I'm using the JSON Server package (json-server) from https://github.com/typicode/json-server. I'd like to make the server prefix all requests with /api/v2. The documentation even gives an example how to do this with the following:
server.use('/api', router)
However I don't want to setup my own server instance but extend the default when running json-server.
Can I somehow use the above statement in a middleware?
Since the router that json-server returns to you is an Express router.
First define all of your /v1, /v2, etc in its own routes file as show below:
// api-routes.js
const express = require('express')
const jsonServer = require('json-server')
const router = express.Router()
const server = jsonServer.create()
const middlewares = jsonServer.defaults()
const v1Router = jsonServer.router('db-v1.json')
const v2Router = jsonServer.router('db-v2.json')
router.use('/v1', v1Router)
router.use('/v2', v2Router)
module.exports = router
Then mount your API router onto /api like so:
const express = require('express')
const apiRoutes = require('./api-routes')
const app = express()
app.use('/api', apiRoutes)
// ...
Should now have /api/v1 and /api/v2. Untested code above, but should give an idea what you need to do.
Related
I have 2 routes:
/api/system/list - list my systems
/api/system/:systemId/books/list - list books of current system
And different file for each API:
systemAPI.js:
const list = router.get('/list', Validate(Validation.list), listHandler)
return {
routes: [list]
}
bookAPI.js:
const list = router.get('/list', Validate(Validation.list), listHandler)
return {
routes: [list]
}
Finally, use the above routes:
express.use('/api/system', systemAPI.routes)
express.use('/api/system/:systemId/book', bookAPI.routes)
The problem is, when I'm entering list-books API (/api/system/:systemId/books/list), its actually calling the list-systems API (/api/system/list)
Update: Solved!
I had 2 main problems:
routes order (in app.use(..))
use different instance of Express.Router() on each API
Refer the answer below for more information.
Try reversing the order of the routes and this will probably solve your problem:
express.use('/api/system/:systemId/book', bookAPI.routes);
express.use('/api/system', systemAPI.routes);
The reason is that express evaluates routes 'greedily' and it will even resolve to partial matches. So, it is important to keep the more specific routes first before the more general ones.
Also, I think you are using the express router wrong according to the documentation the systemAPI:
const express = require('express');
const router = express.Router();
router.get('/list', Validate(Validation.list), listHandler)
module.exports = router;
The bookAPI route:
const express = require('express');
const router = express.Router();
router.get('/list', Validate(Validation.list), listHandler)
module.exports = router;
Finally import the routers and use them:
const express = require('express');
const bookRouter = require('./bookAPI'); //set the file paths based on your file structure
const systemRouter = require('./systemAPI');
const app = express();
app.use('/api/system/:systemId/book', bookRouter);
app.use('/api/system', systemRouter);
As mentioned in express routing guide and this answer, we can create "mini-app" and use it from the main app. However I saw a code where it uses app instead of router in the module
app.js
var express = require('express');
var userRoutes = require('./routes/user');
var app = express();
app.use('/user', userRoutes);
module.exports = app;
routes/user.js
var express = require('express');
var app = express(); // not express.Router() !!
app.get('/:name', function(req, res) {
var userName = req.params.name;
res.render('user.jade', {
userName: userName
});
});
module.exports = app;
I assumed the correct usage in routes/user.js should be
router = express.Router()
instead of
app = express()
but app = express() also works! what are the differences and why router = express.Router() is better?
When you are working with a server where there are many routes, it can be confusing to leave them in a Main file together. The let router = express.Router() option works differently than let app = express().
While the app returns an app object, router will return a small app fragment, similar to the app, where you will use logic to call them later on the Main.
The most important, about your question, is that a router, which is isolated, will not interfere with others in the application, being a single environment.
https://expressjs.com/en/api.html#router
A router object is an isolated instance of middleware and routes. You can think of it as a “mini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.
A router behaves like middleware itself, so you can use it as an argument to app.use() or as the argument to another router’s use() method.
In the nodejs+express application can we have different routes files and include them into a single file. Like as below.
in hotel.routes.js I have few routes like
const express = require("express");
const hotelsCtrl = require("../controllers/hotels.controller");
const router = express.Router();
router
.route("/")
.get(hotelsCtrl.getAllHotels);
module.exports = router;
In the review.routes.js I have few routes like
const express = require("express");
const reviewsCtrl = require("../controllers/reviews.controller");
const router = express.Router();
router
.route("/")
.get(reviewsCtrl.getAllreviews);
module.exports = router;
Now I wanted to include both hotel.routes.js and review.routes.js in the index file and when the route is "/hotel" it should go to hotel.routes.js and when the route is "/review" it should go to review.routes.js
can someone please help in fixing this.
Thanks in advance.
You can do this:
app.use('/hotel', require('./hotel.routes.js'));
app.use('/review', require('./review.routes.js'));
This puts the hotel.routes.js exported router on /hotel and the review.routes.js exported router on /review.
It seems like you've a bit over complicated things by using three files in order to set up a single /hotel route.
You could also just do:
const hotelsController = require("../controllers/hotels.controller");
app.get('/hotel', hotelsController.getAllHotels);
There's really no need for the separate hotel.routes.js file.
Of, alternatively you could put the /hotel in the hotel.routes.js file like this:
const hotelsCtrl = require("../controllers/hotels.controller");
const router = require("express").Router();
router.get('/hotel', hotelsCtrl.getAllHotels);
module.exports = router;
And, then all you have to do in index.js is this:
app.use(require('./hotel.routes.js'));
I have an Express.js application running on https://mydomain.tld/folder. It sets up the route middlewares with
app.use('/path', middleware)
but only the one for the '/' path is working properly. I'm guessing this is because Express is looking for requests on https://mydomain.tld/path instead of on https://mydomain.tld/folder/path.
How can I get Express to process the requests for https://mydomain.tld/folder/path (preferably without having to hard code the path)?
Using a router:
// myRouter.js
var express = require('express')
var router = express.Router()
router.get('/path', middleware)
// other routes...
module.exports = router
Now you can use your router with the relative path you want:
var myRouter = require('./myRouter')
app.use('/folder', myRouter)
Hello guys so i have this two variables i am requiring them for every route i have so i want to globalize them and just add them to the app.js but when i do that it didn't work.
var express = require('express');
var router = express.Router();
i tried to addd them in to my separate file config.js and then i require it in my route and assign it to variable and use it but it is not working.
my config file look like this
/**
* Module dependencies.
*/
var express = require('express'),
favicon = require('serve-favicon'),
logger = require('morgan'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
errorHandler = require('errorhandler'),
path = require('path');
module.exports = function() {
var app = express();
var router = app.Router();
return app;
}();
i get this error all the time :
throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
TLDR: Your router variable is an instance of Router, and should to be initialized inside each of your route files. I can appreciate trying to be as DRY as possible, but doing it this way will not work the way you expect it to. You can save a bit of typing by writing it this way:
var router = require('express').Router();
The longer explanation is that use multiple routes, you need a router for each route. This is to help break up the whole path associated with a request (i.e. /bar/foo/baz) into more manageable chunks.
Let's say your path can start with either /cats or /dogs. In the file where you declare all your middleware, you could write:
var catRoute = require(./routes/cats)
var dogRoute = require(./routes/dogs)
app.use('/cats', catRoute)
app.use('/dogs', dogRoute)
Then, inside cats.js:
var router = require('express').Router();
router.get('/whiskers', (req, res) => {
res.send('Cat whiskers!')
}
module.exports = router;
What this does is tell the app if it gets a path starting with /cats, use the cats route, which is just another piece of middleware. Within the route itself, we don't have to specify /cats/whiskers, only /whiskers because app is only passing down the part of the path after /cats to the cats.
You can nest as many routers as you want. Check out this article for a good example of how to do that.
Hypothetically, you could use only one router