# Light-weight Framework for creating API Services

![Light-ning](Logo.png)
<br>

``Light as a feather, fast as lightning...``

``ES6 only``

## "To the game, Sherlock!"
<br>

```
import app from 'light-ning';
```
```
app.run()
```

#### Important!
<br>

``You need create the "controllers" and "routes" directories
where are you calling "run" method.``

*``create "controllers" directory only if you need to use actions in routes and controllers.``

```"routes" directory must include "app.js" file and import all your route-files therein:```
<br>

```
import './user'
import './articles'
```
etc.

If your node js file (where are you calling "run" method) 
not in root directory, you need to set prefix before the "run":
```
app.set('prefix', 'path to directory');
app.run()
```

## Router:
<br>

```
import { Router } from 'light-ning';
```

#### Actions
<br>

```
Router.routes('/user', [
  {
    method: 'GET',
    path: '/',
    action: 'User@index',
  },
  {
    method: 'GET',
    path: '/:id',
    action: 'User@show',
  },
  {
    method: 'POST',
    path: '/',
    action: 'User@create',
  },
  {
    method: 'PUT',
    path: '/:id',
    action: 'User@update',
  },
  {
    method: 'DELETE',
    path: '/:id',
    action: 'User@destroy',
  },
]);

```

You'll can write ``method`` property 
in any register ``'POST'`` or ``'post'`` etc.

Property "action" it's a path of two parts: ControllerName@Method.
(It work only if you use Controllers).

What action do:
``User@index`` equals ``UserController.index(req, res)``
and pass object with ``req, res, etc.`` options in "index" method. [More below...](#controllers)

*Method for action cannot be `static`.

#### Middlewares
<br>

```
Router.routes('/user', [
  {
    method: 'GET',
    path: '/',
    middleWares: [ firstFunc, secondFunc ],
  },
]);
```

Middlewares performed in succession from left to right. 
For pass the course, you need call "next" in your middleware:

```
const middleware = next => {
    
    if (true) {
        next();
    } else {
        throw new Error('access denied');
    }
        
}
```

You'll can pass data in your middleware like this:

```
const middleware_1 = next => {
    if (true) {
        next(anyData);
    }
}
```
```
const middleware_2 = (data, next) => {
   console.log(data); // anyData
}
```
#### Important!
<br>

``Do not place "middleWares" with "action" in one route. In this case, "middleWares" will be ignored.``
 
``Method name - can be any``

#### Guard
<br>

You'll can use guard property for enable
"guardian" mode.

```
Router.routes('/user', [
  {
    method: 'GET',
    path: '/',
    guard: true,
    action: 'user@index'
  },
]);

```

After enable, you need to set "guardian" 
middleware into "app":

```
const guardian = ({req, next, response}) => {
    
    if (req.body.user === session.user) {
        next();
    } else {
        response({ code: 403 });
    }
        
}
    
app.set('guardian', guardian);
```

``guardian`` middleware get default ``req, res`` node js objects, 
``next`` function for pass the course
and custom ``response`` method for easy reponses. 
[More below...](#response)

#### Root path
<br>

Setting the root path for group routes.

`Do not export "Router"`

```
Router.routes('/user', [
```

```
  {
    method: 'GET',
    path: '/',
    action: 'User@index',
  },
  {
    method: 'GET',
    path: '/:id',
    action: 'User@show',
  },
```

This router create routes like:

```
 /user/
 /user/:id
```
etc.
<a name="controllers" id="controllers" href="controllers"></a>

## Controllers: 
<br>

After route ``action: 'User@index'``, object with data get 
in controller. It looks like: 

```
 {
    req: request, // default node js object
    res: response, // default node js object
    response: Response, // method for easy response
 }
```

#### Important!

Controller class should `export`. (only `export`, not `default export`)

```
export class UserController {
    
  index(data) {
    let {req, res} = data;
  }
    
  show({req, response}) {
    if (req.body.user === session.user) {
        return response({ data: session.user });
    }
  
    response({ code: 403 });
  }
}
```

If you not pass custom error into response object, they get
default error from http-errors dictionary by status code.
<a name="response" id="response" href="response"></a>

Method "Response" has 3 params:
```
{
    error: 'Are you ok?', // custom error
    code: 422, // status code
    data: []
}
```

#### Important!
<br>

* ``"error" must sending with "code" (code can sending without error)``
* ``"data" must sending without "error" (in this case, data will be ignored)``

## Base Controller

You'll can extend your controller from ``BaseController``:
```
import { BaseController } from 'light-ning';
```
```
export class UserController extends BaseController {
    
  filter = ['password']; // es7
    
  constructor() {
    super();
    this.filter = ['password'] // es6
  }
    
  index({response}) {
    let user = {
      login: 'user',
      email: 'user@mail.com',
      password: 'secret'
    };
        
    let data = this.filtrate(user);
    
    console.log(data); // { login: 'user', email: 'user@mail.com' }
    
    response({ data: data });
  }
    
};

```

``BaseController`` has method ``filtrate`` for easy filter data
for response.

``filtrate`` works from ``filterMode`` (``'omit'`` by default).
You'll can set 2 modes:

* ``omit``
* ``pick``

their names speak for themselves.

```
filter = ['password'];
```
Omit mode:
```
filterMode = 'omit';
```
```
this.filtrate({
    login: 'user',
    password: 'secret'
});
    
// result: { login: 'user' }
```
Pick mode:
```
filterMode = 'pick';
```
```
this.filtrate({
  login: 'user', 
  password: 'secret'
});
    
// result: { password: 'secret' }
```


## Configure
<bt>

You'll can create ``config.json`` near your node js file 
(where are you calling "run" method) and set:

```
{
    "port": your port
}
```

or you can set port in app:

```
app.set('port', your port);
app.run();
```

Default port: ``6060``


### [look source on github](https://github.com/sentiurin/light-ning)

