# RAML Validator

Welcome to a new era. An era where we, revmobers, will document every API! 😎

## Why
Because loggin the input payload and response json to understand what's going on sucks 😭

To help us, we will use RAML (**REST**ful **A**PI **M**odeling **L**anguage) to document our code,
and complementary libs ([osprey](https://github.com/mulesoft/osprey)) to validate requests against our doc.

## What is does

Before your request reaches your controllers, raml express middleware will:
 - intercept the request;
 - check where it was going to;
 - validate them against a raml file;
 - return an error if the request payload doesn't meet the criteria

## Default Error Handler

The default error handler will return array of error:

```raml
400:
  body:
    type: object
    properties:
      errors: error[]
    examples:
      invalidResponse:
        errors: [{
            message: 'Validation Error!',
            details: {
                age: 'Missing required property: age',
                name: 'Invalid type, expected string'
            }
        }]
```

The response:
```json
{
    "errors": [{
        "message": "Validation Error!",
        "details": {
            "age": "Missing required property: age",
            "name": "Invalid type, expected string"
        }
    }]
}
```

## Installation

Just do a:

```bash
npm install --save @revmob/raml-validator
```

## How to use

To see an example, just access `examples/express.js`.
The default middleware is created Asyncronously, using promise.
That being said, just pass your Express instance to raml-validator like this:
**ALWAYS** define raml-validator middleware **BEFORE** your routes, otherwise it won't validate your request before your controller processing it

``` javascript

import ramlValidator from 'raml-validator'

const config = {
  path: 'path/to/api.raml'
}

const app = express()

ramlValidator(config)
  .then(({ validator, errorHandler, finalErrorHandler }) =>
    app.use(validator) // MUST come before your routes
     .use(errorHandler) // MUST come before your routes
     .use(myRoutes)
     .use(finalErrorHandler) // SHOULD be the last
   )
  .then(app => app.listen(8080))

```

## Configuration

### Osprey

The config object accepts the following:

``` javascript
const config = {
  path: 'path/to/api.raml', //ABSOLUTE path to raml file
  customErrorHandler: function (req, res, errors, stack) {
    // A custom Error Handler, where you can process invalid requests your way.
  },
  server: {
    cors: true
  },
  security: {
    basicAuth: {
      validateUser: (user, password, done) => {
        if (user === MY_USER && password === MY_PASSWORD) {
          return done(null, true)
        }

        return done(null, false)
      }
    }
  }
}

```

For more details, please refer to osprey documentation for [server](https://github.com/mulesoft/osprey/blob/master/README.md#server-resource-handling) and [security](https://github.com/mulesoft/osprey/blob/master/README.md#security).

### Additional configuration

As of `0.2.0`, this package expose the `hooks` configuration.

This allows you to intercept RAML errors. It's specially useful for logging:

There are 2 different hooks:

- `onValidationError :: (errors: Error[], req: HttpRequest, res: HttpResponse) -> void`: will be called if RAML validation fails.
- `onUnknownError :: (error: Error, req: HttpRequest, res: HttpResponse) -> void`: will be called if something goes wrong with the validation setup.

``` javascript
const config = {
  path: 'path/to/api.raml',
  server: {
    cors: true
  },
  security: {
    basicAuth: {
      validateUser: (user, password, done) => {
        if (user === MY_USER && password === MY_PASSWORD) {
          return done(null, true)
        }

        return done(null, false)
      }
    }
  },
  hooks: {
    onValidationError: (errors, req, res) => {
      errors.map(error => console.log(error))
    },
    onUnknownError: (error, req, res) => {
      console.log(error)
    }
  }
}

```

## I am a hipster and don't use Express.js

If you're not using `express.js` server, feel free to contribute by PRing a new raml middleware! :)

