I'm attempting to use the Express 4 Router to use a different router based on the path. I want all /api/v2/ routes handled by version2, and every other route handled by version1. The below setup serves me all the version1 routes correctly, but seems to ignore version2 as I get a 'Cannot GET...' message each time I test those endpoints.
routes.js:
var version1 = require('./routes/vers1');
var version2 = require('./routes/vers2');
module.exports = function(app) {
app.all('/api/v2/*', version2);
app.all('/*', version1);
};
Method routes (.get, .post, and of course .all) are terminal. This is why you can use wildcards with them as well. .use is not terminal and doesn't allow wildcards -- it acts as a prefix. This is an implementation choice of express. Use .use without wildcards.
.use does not set the layer route
all other methods set the layer route
if the route is set, layer attempts to handle the request. Otherwise, the layer's path is stripped from the request route (/api/v2 that you set in .use will be stripped).
The fact that app.use("/*", version1) works is purely incidental. This will match any route and fall through to version1[method](path). Since there is no prefix to strip, if the request route matches path, express will consider this a match and serve that route.
Use .use.
You want to use .use not .all
.all is for middleware like authentication
http://expressjs.com/api.html
Related
There are two 2 files with routes.
user.route.js
router.get('/user/:id');
user-transaction.js
router.get('/user/transaction');
My architecture looks like this:
src/
user/user.route.js
user-transaction/user-transaction.route.js
I connect all my routes in the project in the following way:
const dirs = await recursive(dir);
dirs.forEach((res) => {
if (res.includes('route')) {
console.log(res);
const path = `#modules/${res}}`;
router.use(require(path));
}
});
The problem is that Express doesn't see the /user/transaction route because it connects later than /user/:id and thinks /user/transaction refers to /user/:id.
It seems logical to just move the route higher, but I connect the routes dynamically. That is, it simply takes the files in order and connects the routes in the same order. Is there a solution to this problem or will I have to manually connect all the routes?
I´m new to next js, I have created a file called orders.js under pages directory, and I can access it correctly from localhost:3000/orders.
However, I want now to have a subroute, to access the order with id 1 (for example). So I have created a directory 'orders' inside the directory pages, and renamed order.js to index.js, after that, I have created another file inside the orders directory called id.js.
So my current structure is:
pages/
orders/
index.js
id.js
However I cannot access to localhost:3000/orders/1.
Using Nuxt js, this was trivial, how can I achieve the same with next.js ?
Thanks
This is also trivial with Nextjs, however, you're trying to achieve it the harder way.
Your first approach is correct. If you don't specify a route for your pages in the server.js file, Nextjs will automatically use them if the URL is correct (in this case orders leads to the orders.js page).
What you're looking for is to create a custom route. You can see the documentation for this here
I find the example in the documentation confusing, so I recommend using express instead. Here's an example for that. You can then see the express routes in the server.js file of the example.
Your route would end up looking something like this:
server.get('/orders/:id', (req, res) => {
return app.render(req, res, '/orders', req.query)
})
Where :id is a query param which you can then access in your getInitialProps inside your orders.js page.
You can check the express routing examples in the express documentation.
You can try using next-routes, dynamic routes for Next.js
And simply create a routes.js and add,
const routes = require('next-routes')
module.exports = routes()
.add('orders', '/orders/:id', 'orders/id')
// name, url, page folder
Or if you only want the server side routing,
server.get('/orders/:id', (req, res) => {
const actualPage = '/orders'
app.render(req, res, actualPage, req.query)
})
This might help you : https://nextjs.org/docs#dynamic-routing.
by adding [ ] to a page it creates a dynamic route, in this case [orderid].js can be used to map multiple orders to a single page.
pages/
orders/
[id].js
use
pages/
orders/
[dynamic_subroute].js
now catch it with
const router = useRoute();
const { dynamic_subroute } = router.query;
Now, you can catch the value (any) dynamically from the url which is used instead of dynamic_subroute
like- if the url is pages/orders/1
then value of dynamic_subroute will be 1 in your page
If router.all() just match all methods,could it be instead by router.use()?
and what router.use() diff between router.route()?
router.all: What this means is, it doesn't matter the method of the request.. (post, get, put), if the url matches, execute the function.
ex- router.all("/abc",fn) will be work for all request to /abc
router.use() : router.use() helps you write modular routes and modules.. You basically define a middle ware for routes.
router.use("/pqr", pqrRoutes)
now for all requests that start with /pqr like /pqr/new or /pqr/xyz can be handles inside the pqrRoutes.
router.route(): this is nice way to define the different Method implementations for a single url end point.
lets just say you have two api end points. router.get("/jkl") and router.post("/jkl"), with router.route() you cam sort of combine these different api handlers..
you can say router.route("/jkl").get(fn1).post(fn2)
router.all() matches every http protocol, router.use() is for middleware, and router.route() returns an instance of a single route which you can then use to handle HTTP verbs with optional middleware.
You should check out the documentation for more informations
app.all(), which is not derived from any HTTP method. This method is used for loading middleware functions at a path for all request methods.
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
Bascially we use .use when we use a middleware
express.Router
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
There can we more than 1 router this instance of router has name router defined below the express defination.
Here is the documentation for router
https://expressjs.com/en/guide/routing.html
Router.use()
Routers behave like middleware and can be .use()d by the app in other routers. In other words, routers allow you to chunk your big app into numerous mini-apps that you can later put together. For small apps, this might be overkill, but as soon as you think, “This app.js file is getting big,” it’s time to think about breaking down your app with routers.
router.route(path)
The router.route(path) method is used to chain HTTP verb methods. For example, in a create, read, update, and
delete (CRUD) server that has POST, GET, PUT, and DELETE endpoints for the /posts/:id URL (e.g., /posts/53fb401
dc96c1caa7b78bbdb), we can use the Router class as follows:
var express = require('express');
var router = express.Router();
router.param('postId', function(request, response, next) {
// Find post by ID
// Save post to request
request.post = {
name: 'Node.js',
url: 'http://your-url/node-js-blog'
};
return next();
});
The Router.route(path) method provides the convenience of chaining methods, which is a more appealing way
to structure, your code than re-typing router for each route.
Alternatively, we can use router.VERB(path, [callback...], callback) to define the routes just as we
would use app.VERB(). Similarly, the router.use() and router.param() methods work the same as app.use() and
app.param().
I have API with Sails.js and I want to wrap all my routes in v1. Is it possible?
Here is what I tried, but it doesn't work.
routes.js
'use strict';
module.exports.routes = {
'/v1': { //
'get /cron': 'CronController.start' // THIS DOES NOT WORK
}, //
'get /cron': 'CronController.start' // this works
};
Based on my knowledge of Sails the only way to wrap all of your routes in /v1 is to first ensure the actions boolean in config/blueprints.js is set to true (it is by default), and then further down in that file set the prefix string to "/v1". Here is the documentation detailing this config.
Note that having the actions boolean set to true causes Sails to generate GET, POST, PUT, and DELETE routes for the action, make sure to use policies to ensure no unsafe logic is exposed in this way.
I am trying to unit test my ExpressJS routes. It looks something like this
server.js
var boards = require('./routes/BoardsRoute.js');
app.get('/api/v1/boards/:id', boards.getBoard);
BoardRoutes.js
exports.getBoard = function(req, res) {
BoardModel.find({
name: 'Kanban Board'
}, function(err, columns) {
if (!err) {
return res.send(columns);
} else {
return console.log(err);
}
});
return res.send(board);
};
I would like to Mock out the BoardModel as this is the call to the Mongoose Model (aka Database call). As I assume that unit tests should not be making calls to a database and have no server running.
Should I be testing the getBoards completely seperatly to the server.js app.get() call.
(As these requests apt.get will be covered by integration tests/e2e tests and they are HTTP requests)
All the documentation and frameworks that I can see either have to have Express Server running in order to unit test the route and this particular exports.getBoard.
Things that I have tried to do,
Use Sinon.js to mock a fakeServer so that I could test the HTTP Request and the method getBoard.
Use SuperAgent and Super Test to make the requests out to a server. (I am uncomfortable with this as unit tests should not have a server running).
I am trying to use Mocha to test these routes.
I would test that the route is wired up correctly first, then test that the call to the route does what you expect.
To test the route here's one way you could do it. Create a routes module that just wires up the routes:
var routes = {};
routes.create = function(app) {
app.get('/api/v1/boards/:id', boards.getBoard);
}
module.exports = routes;
You can then mock the app object and check the get method gets called correctly. (I tend to use Sinon.js for this.) The create method will need to be called from your app module:
var app = express();
... // set up express
routes.create(app);
Now you can focus on testing getBoard on its own like any other module.