# railroad

> Build Node REST API's with the annoying stuff already done for you.

Latest version **0.3.2** (published 2016-06-23) · MIT license · 0 weekly downloads

## Install

```sh
npm install railroad
pnpm add railroad
yarn add railroad
bun add railroad
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.3.2 |
| Published | 2016-06-23 |
| First published | 2016-01-31 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 12 |
| Known vulnerabilities | 0 (+6 in 3 direct dependencies) |
| Install scripts | no |
| Author | Arjan Frans |
| Maintainers | arjanfrans |

## Links

- npm: https://www.npmjs.com/package/railroad
- Repository: https://github.com/arjanfrans/railroad
- Homepage: https://github.com/arjanfrans/railroad#readme
- Issues: https://github.com/arjanfrans/railroad/issues
- npm.io page: https://npm.io/package/railroad

## Dependencies (12)

- [co](https://npm.io/package/co.md) ^4.6.0
- [koa](https://npm.io/package/koa.md) ^1.2.0
- [bcrypt](https://npm.io/package/bcrypt.md) ^0.8.7
- [koa-etag](https://npm.io/package/koa-etag.md) ^2.1.1
- [waterline](https://npm.io/package/waterline.md) ^0.12.2
- [koa-router](https://npm.io/package/koa-router.md) ^5.4.0
- [sails-disk](https://npm.io/package/sails-disk.md) ^0.10.10
- [jsonwebtoken](https://npm.io/package/jsonwebtoken.md) ^7.0.1
- [koa-bodyparser](https://npm.io/package/koa-bodyparser.md) ^2.2.0
- [recursive-readdir](https://npm.io/package/recursive-readdir.md) ^2.0.0
- [koa-conditional-get](https://npm.io/package/koa-conditional-get.md) ^1.0.3
- [waterline-model-loader](https://npm.io/package/waterline-model-loader.md) ^0.2.0

## Recent versions

- 0.3.2 (latest) — 2016-06-23
- 0.3.1 — 2016-06-16
- 0.3.0 — 2016-04-27
- 0.2.3 — 2016-04-26
- 0.2.2 — 2016-04-25
- 0.2.1 — 2016-02-24
- 0.2.0 — 2016-02-15
- 0.1.0 — 2016-02-07
- 0.0.1 — 2016-01-31

## README

# Railroad

[![npm version](https://img.shields.io/npm/v/railroad.svg)](https://www.npmjs.com/package/railroad)
[![Build Status](https://travis-ci.org/arjanfrans/railroad.svg?branch=master)](https://travis-ci.org/arjanfrans/railroad)
[![Coverage Status](https://coveralls.io/repos/arjanfrans/railroad/badge.svg)](https://coveralls.io/r/arjanfrans/railroad)
[![Dependency Status](https://david-dm.org/arjanfrans/railroad.svg)](https://david-dm.org/arjanfrans/railroad)
[![devDependency Status](https://david-dm.org/arjanfrans/railroad/dev-status.svg)](https://david-dm.org/arjanfrans/railroad#info=devDependencies)
[![Shitty logo, help me!](./logo.png?raw=true)](#)

Basic framework for rest api's based on [koa](http://koajs.com/) and uses [Waterline](https://github.com/balderdashy/waterline) models.

Features:
* Automatic REST controllers with support for authentication and authorization.
* Authentication middleware (Json Web Tokens or custom implementation).
* Configure ACL for controllers and actions.
* ACL based on the current user (e.g. a user can only edit itself).
* Pagination
* Etag and Conditional GET

## Usage

```javascript
let koa = require('koa');

let Railroad = require('railroad');
let config = require('./config');

let app = koa();

Railroad(app, config, {
    acl: require('./acl'),
    auth: require('./auth')
}).then(() => {
    app.listen(3000);
}).catch((err) => {
    console.log(err.stack);
});
```

## Configuration

```javascript
// config.js

let path = require('path');
let connections = require('./connections');
let routes = require('./routes');

module.exports = {
    // Path to the controllers directory
    controllers: path.join(__dirname, 'controllers'),

    // Path to the models directory
    models: path.join(__dirname, 'models'),

    connections: connections,
    routes: routes,

    // Options for resource controllers/actions.
    resource: {
        pagination: true, // turn on pagination
        pageLimit: 50 // If pagination is turned on, set the limit per page
    }

    // Options for Json Web Tokens (if you want to use it)
    jwt: {
        expiresIn: 180 * 60,
        secret: 'secret'
    }
};
```

### Database connections
The database connection configuration is a configuration object for the Waterline ORM.

```javascript
// connections.js

let diskAdapter = require('sails-disk');

/**
 * Waterline ORM config.
 */
module.exports = {
    adapters: {
        default: diskAdapter,
        disk: diskAdapter
    },

    connections: {
        myLocalDisk: {
            adapter: 'disk'
        }
    },

    defaults: {
        connection: 'myLocalDisk',
        migrate: 'safe'
    }
};
```

## Resource Controllers

A resource controller will provide all the CRUD operations for a model. It taps into the
authentication and authorization functionality. It will use the global pagination configuration, or you can
pass an optional options object. A `Resource` will return an object. Example:

```javascript
let Resource = require('railroad/lib/utils/Resource');

// model name and optional "resource" options
module.exports = Resource('User', { pagination: false });
```

A resource has the following methods:

* **find**: GET method, returns an array with resources.
* **findOne**: GET method, returns a single resource
* **create**: POST method, create a resource and return it.
* **update**: PATCH method, update a resource and return it.
* **destroy**: DELETE method, delete a resource.

If you do not need all methods, you could make your own controller and use the action
helpers individually (located in `railroad/lib/utils/ResourceAction`).

### Pagination
By default a `Resource` has pagination on the `find` method. Query parameters `page` and `limit` are used to control the pagination.
A response will include Link Headers for navigation to other pages.

To turn off pagination pass the following option into the resource function:

```javascript
Resource('User', { pagination: false });
```

## Routes
The routes configuration maps paths to controllers or actions. For a resource controller,
just use the path. For a custom controller action, add the method as a prefix.
Example route configuration:

```javascript
// routes.js

module.exports = {
    '/product': 'ProductController', // Resource route
    'get /product/custom': 'ProductController.custom', // Custom route
    'get /product/custom/:title': { // Custom route alternate syntax
        controller: 'ProductController',
        action: 'customOne'
    },
    '/pet': 'animals/PetController' // Nested file
};
```

## Authentication

A middleware is used to authenticate a user. An example:

```javascript
// auth.js

module.exports = function* (next) {
    if (!this.state.route.requiresAuth) {
        return yield next;
    }

    this.state.user = {
        id: 2,
        name: 'Test User',
        isAdmin: false
    };

    return yield next;
};
```

Railroad includes an auth middleware and controller that uses Json Web Tokens.
See the example.

## Authorization
The ACL file must export a function with the user as it's argument.
An object explaining the rights of the user must be returned from this function.

Properties names of this object can be controller names, (action names nested within a controller)
or `*` for defining the default ACL.

Values can be a *boolean*, *function* or an *object*.

* *boolean*: When set to `true`, authentication is required.
* *object*: Authentication is required, but authorization depends on the accessed resourced. The object will describe
criteria that applies to the [Waterline](https://github.com/balderdashy/waterline) model. It is basically a *where* clause.
* *function*: Authentication is required, but the outcome of the function will decide if a user has access.
A function can either return a *boolean* or an *object*. Depennding on the type, one of the previous rules will apply.

```javascript
module.exports = function (user) {
    return {
        '*': true, // All routes protected by default
        'animals/PetController': false, // Allow PetController
        ProductController: {
            find: {
                userId: user.id
            },
            custom: true, // Require auth
            customOne: () => user.isAdmin, // Conditional Acl with a function
            create: false,
            findOne: {
                userId: user.id // Conditions for the Waterline model
            },
            update: {
                userId: user.id
            },
            destroy: {
                userId: user.id
            }
        }
    }
};
```

## Context added by Railroad

* **ctx.config**: The railroad configuration object.
* **ctx.state.route.controllerName**: Name of the current controller.
* **ctx.state.route.actionName**: Name of the current action.
* **ctx.state.route.path**: Path as defined in the route configuration.
* **ctx.state.route.method**: Method of the current route.
* **ctx.state.route.requiresAuth**: Check if the current route requires authentication.
* **ctx.state.user**: The current user.
* **ctx.state.route.acl.authenticated**: If the current user is authenticated.
* **ctx.state.route.acl.authorized**: If the current user is authorized to access the current route.
* **ctx.state.route.acl.criteria**: Criteria for the current route as defined in the *acl* middleware.

---
_Source: https://npm.io/package/railroad · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
