Rcls
Rcls

Reputation: 479

Node.js API design and route handling

I am not really sure what to title this, but I'm new to Node.js. I just found a neat REST API project on GitHub to implement but I'm not sure how I can split all GET and POST etc. to separate files.

I have one singular api.js file where I have

function API_ROUTER(router, connection, md5) {
    var self = this;
    self.handleRoutes(router, connection, md5);
}

API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
    router.get("/", function(req, res) {
        res.json({"Message" : "Hello World !"});
    });
};

module.exports = API_ROUTER;

Now how can I create a sibling other.js and use:

var api = require('./api.js');

// Create router.get, router.post etc. here?

Upvotes: 2

Views: 1181

Answers (2)

t.niese
t.niese

Reputation: 40842

If you implement a RESTful API, then you should keep in mind that this is just one way how you can provide data, and you might want to change it in future, as of that the API will most of the time only be a translation layer.

Normally you will split your code based on the resources, and the code that is handling the request won't have so much logic, it will just take the request and pass it to you internal API. For that purpose you not really need an additional layer if you already use express.js or a similar library.

In express the app.use([path,] function [, function...]), already provides the functionality you would need to modularize your code. For each resource your will create an own express.Router that itself also might mount another sub module. So for this part you do not really need a library.

When might a library be useful:

  • if it automatically translates thrown errors to the correct response codes
  • if it includes a tool to automatically create a documentation to your API
  • if it fully abstracts the underlaying routing system so that you can hook into express, hapi, ... without the need to change the code.

Here how a setup with express.js could look like

./lib/rest/customer.js

var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();

router.get('/:id', function(req, res, next) {
  customerSystem.find({
    id: req.params.id
  }, function(err, customer) {
    if (err) {
      res.status( /*correct status code*/ ).send( /*depending on the api return json, xml, ....*/ )
    } else {
      res.send( /*depending on the api return json, xml, ....*/ )
    }
  })
});

router.delete('/:id', function(req, res, next) {
  customerSystem.delete({
    id: req.params.id
  }, function(err) {
    //...
  });
});


router.post('/', function(req, res, next) {
  //...
});

//save the customer id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
  req.customerId = req.params.id;
  next();
});

router.use('/:id/addresses', require('./customer-address') )

module.exports = router;

./lib/rest/customer-address.js

var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();

router.get('/:id', function(req, res, next) {
  customerSystem.find({
    id: req.customerId
  }, function(err, customer) {
   // ...
  })
});

/* ..... */

//save the address id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
  req.addressId = req.params.id;
  next();
});

router.use('/:id/addresses', require('./customer-address') )

module.exports = router;

Upvotes: 1

nem035
nem035

Reputation: 35491

but I'm not sure how I can split all GET and POST etc. to separate files.

One way you can organize your routes would be to have a separate object for each route that has the handlers (separated by HTTP methods) and other needed info such as the path:

api/home.js

module.exports =  {
   path: '/',
   handlers: {
     'get': function(req, res) {
          res.json({"Message" : "Hello World !"});
      },
      'post': { 
        // ...
      }
      // ...
    }
}

api/other.js

module.exports =  {
   path: '/other',
   handlers: {
     'get': function(req, res) {
        res.json({"Message" : "Other !"});
      },
    // ...

Then you can load all of these inside the handleRoutes method:

API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
   var routes = ['home', 'other'];

   routes.forEach(function(name) {
     // load the current route object (NOTE: you should use the path module for determining file path in a cross-platform manner)
     var routeObject = require('./' + name + '.js');

     var apiPath = routeObject.path;
     var handlers = routeObject.handlers;
     var methods = Object.keys(handlers);

     // assign handlers for each method
     methods.forEach(function(method) {
       router[method](apiPath, handlers[method]);
     });

   });
};

This will install all your routes with the appropriate information and handlers. Now you can call this code by instantiating your API_ROUTER with the necessary data:

// initialize the api (and handle the routes internally)
var Api = new require('./api.js')(router, connection, md5);

Upvotes: 1

Related Questions