Coder Social home page Coder Social logo

ukayani / restify-router Goto Github PK

View Code? Open in Web Editor NEW
52.0 17.0 15.0 222 KB

A router interface for restify that lets you aggregate route definitions and apply to a restify server

License: MIT License

JavaScript 93.86% TypeScript 6.14%
restify router routing express-router organization

restify-router's Introduction

Restify Router

Build Status

This module allows you to define your routes using a Router interface that is identical to how routes are registered on a restify server. You can then apply the routes to a server instance.

Borrowing from the idea of Express router where you can organize routes by creating multiple routers and applying them to an express server, this component allows you to achieve a similar separation/grouping of route definitions.

Summary

Installation

$ npm install --save restify-router

Creating a router

A router object is an isolated instance of routes. The router interface matches the interface for adding routes to a restify server:

var Router = require('restify-router').Router;
var routerInstance = new  Router();
var restify = require('restify');

function respond(req, res, next) {
  res.send('hello ' + req.params.name);
  next();
}

// add a route like you would on a restify server instance
routerInstance.get('/hello/:name', respond);

var server = restify.createServer();
// add all routes registered in the router to this server instance
routerInstance.applyRoutes(server);

server.listen(8080, function() {
  console.log('%s listening at %s', server.name, server.url);
});

Why use it?

When your application starts to contain a lot of routes, you may want to group the definition of routes in separate files rather than registering every route in a single server bootstrap/creation file.

For example, if we have two sets of routes in our application:

Users:

  • GET /users
  • GET /users/:id

Posts:

  • GET /posts
  • GET /posts/:id
var userRouter = require('./user.router'); // return a Router with only user route definitions
var postsRouter = require('./posts.router'); // return a Router with only posts route definitions

var restify = require('restify');
var server = restify.createServer();

// add user routes
userRouter.applyRoutes(server);

// add posts routes
postsRouter.applyRoutes(server);

server.listen(8080, function() {
  console.log('%s listening at %s', server.name, server.url);
});

Prefixing Routes

To prefix all routes, specify the prefix as the second argument to router.applyRoutes(server, prefix)

  • prefix must be a string or a regex

Example:

Routes:

  • GET /admin/settings
  • GET /admin/controls
var Router = require('restify-router').Router;
var restify = require('restify');

function settings(req, res, next) {
  res.send('settings');
  next();
}

function controls(req, res, next) {
  res.send('controls');
  next();
}

var routerInstance = new Router();

// add a route like you would on a restify server instance
routerInstance.get('/settings', settings);
routerInstance.get('/controls', controls);

var server = restify.createServer();
// add all routes registered in the router to this server instance with uri prefix 'admin'
routerInstance.applyRoutes(server, '/admin');

server.listen(8080, function() {
  console.log('%s listening at %s', server.name, server.url);
});

Nesting Routers

If you are familiar with Express style routers, you have the ability to nest routers under other routers to create a hierarchy of route definitions.

To nest routers use the .add method on a Router:

router.add(path, router);
  • path - a string or regexp path beginning with a forward slash (/)
    • All routes defined in the provided router will be prefixed with this path during registration
  • router - the router instance to nest

Example Usage

// routes/v1/auth.js

const router = new Router();
router.post("/register", function (req, res, next) {
 // do something with req.body
 res.send({status: 'success'});
 return next();
});

module.exports = router;
// routes/v1/routes.js

const router = new Router();
router.add("/auth", require("./auth"));

module.exports = router;
// routes/routes.js

const router = new Router();
router.add("/v1", require("./v1/routes"));

module.exports = router;

With the above router definition from routes/routes.js we can do the following call:

POST /v1/auth/register

This call is possible because we have nested routers two levels deep from the /v1 path.

Grouping Routers

As an alternative to Nesting Routers, you can use the group to clarify the middlewares manipulation and the routes / files organization. Works in a way that does not need to create multiple instances of the Router like Nesting.

To group routers use the .group method on a Router:

router.group(path, callback);

Example Usage

Basic Usage

var Router = require('restify-router').Router;
var restify = require('restify');

var routerInstance = new  Router();
var server = restify.createServer();

routerInstance.get('/', function (req, res, next) {
  res.send({message: 'home'});
  return next();
});

routerInstance.group('/v1', function (router) {
  router.get('/', function (req, res, next) {
    res.send({message: 'home V1'});
    return next();
  });

  router.group('/auth', function (router) {
    router.post('/register', function (req, res, next) {
      res.send({message: 'success (v1)'});
      return next();
    });
  });
});

routerInstance.group('/v2', function (router) {
  router.get('/', function (req, res, next) {
    res.send({message: 'home V2'});
    return next();
  });
});

// add all routes registered in the router to this server instance
routerInstance.applyRoutes(server);

server.listen(8081, function() {
  console.log('%s listening at %s', server.name, server.url);
});

With the above code definition we can do the following calls:

  • GET /
  • GET /v1
  • POST /v1/auth/register
  • GET /v2

Basic Usage with nesting Middlewares

var Router = require('restify-router').Router;
var restify = require('restify');

var routerInstance = new  Router();
var server = restify.createServer();

function midFirst(req, res, next) { /**/ }
function midSecond(req, res, next) { /**/ }
function midThird(req, res, next) { /**/ }

routerInstance.group('/v1', midFirst, function (router) {
  router.get('/', function (req, res, next) {
    res.send({message: 'home V1'});
    return next();
  });

  router.group('/auth', midSecond, function (router) {
    router.post('/register', midThird, function (req, res, next) {
      res.send({message: 'success (v1)'});
      return next();
    });
  });
});

// add all routes registered in the router to this server instance
routerInstance.applyRoutes(server);

server.listen(8081, function() {
  console.log('%s listening at %s', server.name, server.url);
});

With the above code definition we can do the following calls:

  • GET /v1 [midFirst]
  • POST /v1/auth/register [midFirst, midSecond, midThird]

Common Middleware

There may be times when you want to apply some common middleware to all routes registered with a router. For example, you may want some common authorization middleware for all routes under a specific router.

All middleware registered via .use will be applied before route level middleware.

To stay consistent with the restify server interface, the method on the Router is:

  • .use(middlewareFn, middlewareFn2, ...)
  • .use([middlewareFn, middlewareFn2, ...])

Note: Multiple calls to .use will result in aggregation of middleware, each successive call will append to the list of common middleware

Example Usage

var router = new Router();

// this will run before every route on this router
router.use(function (req, res, next) {
   if (req.query.role === 'admin') {
    return next();
   } else {
    return next(new errors.UnauthorizedError());
   }
});

router.get('/hello', function (req, res, next) {
   res.send('Hello');
   next();
});

router.get('/test', function (req, res, next) {
   res.send('Test');
   next();
});

router.applyRoutes(server);

// calling GET /hello  runs use middle ware first and then the routes middleware

Links

For more information about Restify Router see Organizing Restify Routes with Restify Router

restify-router's People

Contributors

budnieswski avatar jimmywarting avatar otaviotech avatar ukayani avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

restify-router's Issues

Problem with nested functions via router.add

I'm experiencing an issue when I updated restify to the last version.

Some routes that I have added via de .add function seems to not being added to the server and it responds with:
{ "code": "ResourceNotFound", "message": "/api-partners/panel does not exist" }

I've made an example repo here: https://github.com/Cuxs/restify-router-error-sample

To further explain the problem, i have this folders:
image

Each of those x.routes have this code:

const { Router } = require('restify-router');

const routes = new Router();

const handleRouteA= (req,res)=>res.send({status:'ok', message:'Route A'})

routes.get('/', handleRouteA);

module.exports = { routes };

And this is the code of the routes.js file:

const { Router } = require('restify-router');
const { routes: aRoutes } = require('./a/a.routes');
const { routes: bRoutes } = require('./b/b.routes');
const { routes: cRoutes } = require('./c/c.routes');

const routes = new Router();

const handleAnotherRoute = (req,res)=>res.send(401)

routes.add('/panel/a', aRoutes); // businessUser module routes.
routes.add('/panel/b', bRoutes); // businessUser module routes.
routes.add('/panel/c', cRoutes); // businessUser module routes.

routes.get('/another-route', handleAnotherRoute)

module.exports = { routes };

Using the add function, I added that routes to my index.js file:

//...
router.add('/api-partners', moreRoutes.routes);
//...

If I try to fetch to /api-partners/another-route the response I get is:
image

This is correct, but if I try to fetch /api-partners/panel/a the response I get is:

image

I don't know what might be causing this, this problem appears when I updated restify to it's last version (@8.5.1), I update restify-router too, but that not seems to fix the problem.

Hope I explained myself. Thanks in advance!

Recursive routers

I'm very used to the Express-way of handling routes. Is is possible to make these routers use another router?

The Express-way I'm talking about is as following:

// routes/routes.js
router.use("/v1", require("./v1/routes"));

// routes/v1/routes.js
router.use("/auth", require("./auth"));

// routes/v1/auth.js
router.post("/register", function (req, res, next) {});

The following code, in Express, would allow me to call POST /v1/auth/register and it'd simply work. Is the same possible using this module?

Data in body is not parsed

I am sending the body as a JSON and I put the relevant plugins in restify

When I add the "testify-routes" the req.params is not parsing the body of the request so I am not able to use them

Regards

Upload file with multer

When I use with only restify
I use:

server.post('/upload', uploads.single('foto'), async (req, res, next)=>{
    
      try {
          res.send( saveObj  )
      } catch (error) {
          res.send(error)
      }
      next()
  })

But if I use with restify-router, I get this wrong

Argument of type 'RequestHandler' is not assignable to parameter of type 'RequestHandlerType'.
Type 'RequestHandler' is not assignable to type 'RequestHandler'.
Types of parameters 'req' and 'req' are incompatible.
Type 'Request' is missing the following properties from type 'Request<ParamsDictionary, any, any>': get, acceptsCharsets, acceptsEncodings, acceptsLanguages, and 20 more.ts(2345)

issue

Is possible to do upload with restify-router?

Support object as first argument when defining methods for a Route

Currently, a string is used as first argument to any Route method (get, put, post, etc.)
This prevents us from supplying version and other parameters to a route (or at least I have not found a way in current version of restify-router).

Please, add this feature or tell me if you encourage PRs. I'll try to do my best in this case :)

Use joi with restify-router

I am trying to add a validation using joi like this

sme.get('/country/:country/state/:state/city/:city',validator, function(req, res, next) {
})

Can you please comment if it is possible to use joi adaptor like restify-joi-middleware
with restify-router

thanks
tuhin

Using restify-validations-engine

I want to use this validation engine, however I can't seem to figure out where to add the validate option.

Its supposed to be added like this. Any help will be much appreciated.

server.get({
    url: '/my-url',
    validate: { // Entry point of the module
        params: { // Which scope
            myParam: { // The field to validate
                required: true // A validator
            }
        }
    }
});

Nested routers don't process commonHandlers in order

If we use nested routers each with their own set of commonHandlers, the middleware of the deepest router executes first.

it('Should process middlewares in order', function (done) {
      var v1 = new Router();
      var auth = new Router();
      var register = new Router();

      var first = function (req, res, next) {
        req.test = [1];
        next();
      };

      var second = function (req, res, next) {
        req.test.push(2);
        next();
      };

      var third = function (req, res, next) {
        req.test.push(3);
        next();
      };

      register.post('/register', function (req, res, next) {
        res.send({status: 'success', name: req.body.name, commonHandlerInjectedValues: req.test});
        return next();
      });

      auth.use(second, third)
      auth.add('/auth', register);
      v1.use(first)
      v1.add('/v1', auth);

      v1.applyRoutes(server);

      request(server)
        .post('/v1/auth/register')
        .set('Content-Type', 'application/json')
        .send({name: 'test'})
        .expect(200)
        .end(function (err, res) {
          if (err) {
            return done(err);
          }

          res.body.should.deep.equal({status: 'success', name: 'test', commonHandlerInjectedValues: [1,2,3]});
          done();
        });

    });

The test case would fail.

Chaining handlers

Is there any way to chain handlers using this library? I tried to but after I return calling next() the next function doesn't get called.

router.get(
    '/foo/:id',
    function(req, res, next) {
        console.log('Authenticate!');
        return next();
    },
    function(req, res, next) {
        res.send(200);
        return next();
    }
);

Error handler is always executed

Does this library support adding error-handling middleware via router.use()? I'm trying to create a generic handler for a router, but it's being executed before the route handlers.

Example:

app.get('/api/data', function dataHandler(req, res, next) {
    // Process request
});


// Always executes before `dataHandler()`. 
app.use(function errorHandler(err, req, res, next) {
    // Handle error
});

Problem in combination with node-restify-validation npm module

Hi.

I was using restify-router alone and then I have added node-restify-validation module and now I am getting errors. I am using nested routers with routes folder, v1 subfolder and auth.js route file.

The excerpt from auth.js file

router.post({ url: '/register', validation: {
    content: {
        name: { isRequired: true },
        email: { isRequired: true, isEmail: true },
        password: { isRequired: true }
    }
}}, function (req, res, next) {

Error:

TypeError: path must be string or RegExp
    at toRegex (/node_modules/restify-router/lib/path.js:19:9)
    at concat (/node_modules/restify-router/lib/path.js:59:16)
    at /node_modules/restify-router/lib/router.js:131:24
    at Array.forEach (<anonymous>)
    at /node_modules/restify-router/lib/router.js:127:27
    at Array.forEach (<anonymous>)
    at Router.applyRoutes (/node_modules/restify-router/lib/router.js:122:11)
    at /node_modules/restify-router/lib/router.js:144:12
    at Array.forEach (<anonymous>)
    at Router.applyRoutes (/node_modules/restify-router/lib/router.js:139:16)
    at /node_modules/restify-router/lib/router.js:144:12
    at Array.forEach (<anonymous>)
    at Router.applyRoutes (/node_modules/restify-router/lib/router.js:139:16)
    at NativeConnection.db.once (server.js:39:16)
    at Object.onceWrapper (events.js:273:13)
    at NativeConnection.emit (events.js:182:13)

I already did some console.log outputs and I am getting in the toRegex function in path.js

/v1/auth
undefined

I think the problem is it is not picking up the url property.

Best regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.