1.0.9 • Published 8 years ago

prorestify v1.0.9

Weekly downloads
5
License
ISC
Repository
bitbucket
Last release
8 years ago

prorestify

Tired of spending time organizing your project as you scale?

Tired of all these APIs with random URLs and returning random HTTP codes?

This module is made for you!

  • prorestify is a RESTful scalable express router using promises
  • Version 1.0.0
  • Authors: Javier Rodriguez-Uria & Patrick Mettraux

Installation

$ npm install prorestify

Setup

let app = require('express')();
let prorestify = new require('prorestify')();

prorestify.router(app);

app.listen(8080)

Options

You can pass an object to change the default behaviour. Available options:

NameDescriptionDefault
routeFolderThe path where your routes are located./routes/
allowUnknownDefines if you allow unknown parameters during your endpoints' validationfalse
abortEarlyDefines if you stop validation on the first errorfalse

WorkFlow

The module execute actions in this order:

HTTP Request -> Endpoint's Middlewares -> Endpoint's Validation -> Endpoint's Controller

Endpoints

Structure-wise

Endpoints are based on the folder structure of your project. The modules will scan the routes folder.

Directory structure example:

├── project/
│   ├── routes/
│   │   ├── v1/
│   │   │   ├── groups/
│   │   │   |   ├── users.js
│   │   │   ├── users/
│   │   │   |   ├── groups.js
│   │   │   ├── users.js
│   │   │   ├── groups.js
│   ├── app.js

In the example above, if you want to create the following routes:

  • GET->https://yourwebsite.com/v1/users you will have to put the code inside the file located in /project/routes/v1/users.js
  • GET->https://yourwebsite.com/v1/groups you will have to put the code inside the file located in /project/routes/v1/groups.js
  • GET->https://yourwebsite.com/v1/users/:userId/groups you will have to put the code inside the file located in /project/routes/v1/users/groups.js
  • POST->https://yourwebsite.com/v1/groups/:groupId/users you will have to put the code inside the file located in /project/routes/v1/groups/users.js

Code-wise

Now that you know how to organize your files and folders according to the kind of endpoint you are trying to do we can have a look at the code itself.

Inside the right file the module is looking for a specific function named accordingly to the type of endpoint you want to do. This function must return an object containing at least a key named controller assigned to the controller function of this endpoint. This is a list on how to name you function accordingly to what kind of endpoint you want to create.

CREATE

A create is a POST call on a collection. Eg: POST->https://yourwebsite.com/v1/users/

module.exports = {
  create: function(app) {
    let controller = body => {
      // put your code inside here
      return app.yourUserCreationFunction(body);
    };

    return {
      controller,
    };
  }
};

LIST

A list is a GET call on a collection. Eg: GET->https://yourwebsite.com/v1/users/

module.exports = {
  list: function(app) {
    let controller = query => {
      // put your code inside here
      return app.yourUserListingFunction(query);
    };

    return {
      controller,
    };
  }
};

GET

A get is a GET call on an item. Eg: GET->https://yourwebsite.com/v1/users/:userId

module.exports = {
  get: function(app) {
    let controller = (query, params) => {
      // put your code inside here
      return app.yourGetUserFunction(params.userId);
    };

    return {
      controller,
    };
  }
};

UPDATE

An update is a PUT call on an item. Eg: PUT->https://yourwebsite.com/v1/users/:userId

module.exports = {
  update: function(app) {
    let controller = (body, params) => {
      // put your code inside here
      return app.yourUpdateUserFunction(params.userId);
    };

    return {
      controller,
    };
  }
};

PATCH

A patch is a PATCH call on an item. Eg: PATCH->https://yourwebsite.com/v1/users/:userId

module.exports = {
  patch: function(app) {
    let controller = (body, params) => {
      // put your code inside here
      return app.yourPatchUserFunction(params.userId);
    };

    return {
      controller,
    };
  }
};

DELETE

A delete is a DELETE call on an item. Eg: DELETE->https://yourwebsite.com/v1/users/:userId

module.exports = {
  del: function(app) {
    let controller = (body, params) => {
      // put your code inside here
      return app.yourDeleteUserFunction(params.userId);
    };

    return {
      controller,
    };
  }
};

POST action

A post action is a non-CRUD POST call. It can be on an item or a collection. You need to specify in the returned object the target using a key set to item or collection. You can use the same code for both if you want as you can see in the following example.

  • Eg: POST->https://yourwebsite.com/v1/users/:userId/hire => type: item
  • Eg: POST->https://yourwebsite.com/v1/users/hire => type: collection
module.exports = {
  hire: function(app) {
    let controller = (body, params) => {
      // put your code inside here
      return app.yourHireUserFunction(params.userId);
    };

    return {
      item: {
        controller
      },
      collection: {
        controller
      }
    };
  }
};

GET action

A get action is a non-CRUD GET call. It can be on an item or a collection. You need to specify in the returned object the target using a key set to item or collection. You can use the same code for both if you want as you can see in the following example.

  • Eg: GET->https://yourwebsite.com/v1/users/:userId/home-address => type: item
  • Eg: GET->https://yourwebsite.com/v1/users/home-address => type: collection
module.exports = {
  getHomeAddress: function(app) {
    let controller = (query, params) => {
      // put your code inside here
      return app.yourGetHomeAddressUserFunction(params.userId);
    };

    return {
      item: {
        controller
      },
      collection: {
        controller
      }
    };
  }
};

Naming Conventions

URLs

Our RESTful API is going to generate URLs with the collections' names using the plural form. This is also why your files and folders must be using the plural form too. We do not allow camelCase inside an URL. You must you dashes. Eg:

- GET=>https://yourwebsite.com/v1/users/:userId/homeAddress - This is WRONG
+ GET=>https://yourwebsite.com/v1/users/:userId/home-address - This is CORRECT

POST actions

POST actions are meant to be read like an order. For an URL like POST=>https://yourwebsite.com/v1/users/login you must read it like "User login!". An Action is like an order this is why unless a GET call we do not preppend post to the function's name. (reminder, a get action looks like this getHomeAddress)

Because of this naming all CRUD endpoints cannot be called like a post action. This means the following:

  • POST=>https://yourwebsite.com/v1/users/create - this url is impossible
  • POST=>https://yourwebsite.com/v1/users/get - this url is impossible
  • POST=>https://yourwebsite.com/v1/users/list - this url is impossible
  • POST=>https://yourwebsite.com/v1/users/patch - this url is impossible
  • POST=>https://yourwebsite.com/v1/users/delete - this url is impossible

Middlewares

This module handles middleware.

Endpoint's specific

If you want to use some middlewares only on one specific endpoint your endpoint function must return a middlewares array containing your middlewares. See the following example.

module.exports = {
  create: function(app) {
    let middlewares = [
      yourSpecificMiddleware1,
      yourSpecificMiddleware2,
    ];

    let controller = body => {
      // put your code inside here
      return app.yourUserCreationFunction(body);
    };

    return {
      controller,
      middlewares
    };
  }
};

Validation

This module uses joi for the validation of what comes into an endpoint.

By default the module will reject all sent parameters that are not specified in your validation schema. If you want to add a validation schema your endpoint function must return a validation Joi object. See the following for an example.

var Joi = require('prorestify').joi;

module.exports = {
  create: function(app) {
    let validation= Joi.object().keys({
      firstName: Joi.string().min(3).max(50)required(),
      lastName: Joi.string().min(3).max(50)required(),
      email: Joi.string().email(),
    }),

    let controller = body => {
      // put your code inside here
      return app.yourUserCreationFunction(body);
    };

    return {
      controller,
      validation
    };
  }
};
1.0.9

8 years ago

1.0.8

8 years ago

1.0.7

8 years ago

1.0.6

8 years ago

1.0.5

8 years ago

1.0.4

8 years ago

1.0.3

8 years ago

1.0.2

8 years ago

1.0.1

8 years ago

1.0.0

8 years ago