dinevillar / adonis-json-api-serializer

An AdonisJS framework wrapper for https://github.com/danivek/json-api-serializer to have API response formatted according to the JSON API Specification (http://jsonapi.org/)
MIT License
16 stars 3 forks source link
adonis-framework adonis-serializer adonisjs adonisjs-json-api json-api json-api-serializer rest-api

Installation

npm i @dinevillar/adonis-json-api-serializer

Setup

Create/edit config/jsonApi.js.

module.exports = {
      "globalOptions": {
          "convertCase": "snake_case",
          "unconvertCase": "camelCase"
      },
      // Register JSON API Types here..
      "registry": {
          "user": {
              "model": 'App/Models/User'
              "structure": {
                  "links": {
                      self: (data) => {
                          return '/users/' + data.id
                      }
                  },
                  "topLevelLinks": {
                      self: '/users'
                  }
              }
          }
      }
  };

Add as provider (start/app.js)

const providers = [
    '@dinevillar/adonis-json-api-serializer/providers/JsonApiProvider'
]

Add to your Models

static get Serializer() {
return 'JsonApi/Serializer/LucidSerializer'; // Override Lucid/VanillaSerializer
};

Add as named Middleware in start/kernel.js

const namedMiddleware = {
jsonApi: 'JsonApi/Middleware/Specification'
};

Use in your routes

// All request and response to /user must conform to JSON API v1
Route.resource('user', 'UserController')
.middleware(['auth', 'jsonApi'])

You can use the "cn" and "ro" schemes of the middleware.

  • Adding "cn" (jsonApi:cn) will allow middleware to check for Content Negotiation
  • Adding "ro" (jsonApi:ro) will allow middleware to check if request body for POST and PATCH conforms with JSON API resource object rules
  • Adding "ro" (jsonApi:ro) also will automatically deserialize resource objects.
  • If none is specified then both will be applied

Usage

model.toJSON():

getUser({request, response}) {
  const user = await User.find(1);
  response.send(user.toJSON());
};

with relations:

config/jsonApi.js

"registry": {
"company": {
"model": 'App/Models/Company',
"structure": {
id: "id",
links: {
self: (data) => {
return '/companies/' + data.id
}
}
}
}
"user": {
"model": 'App/Models/User',
"structure": {
"links": {
self: (data) => {
return '/users/' + data.id
}
},
"relationships": {
company: {
type: 'company',
links: {
self: '/companies'
}
}
}
"topLevelLinks": {
self: '/users'
}
}
}
}

App/Models/Company

static get Serializer() {
return 'JsonApi/Serializer/LucidSerializer';
};

App/Models/User

static get Serializer() {
return 'JsonApi/Serializer/LucidSerializer';
};

Somewhere:

getUser({request, response}) {
const user = await User.find(1);
await user.load('company'); // load relation
response.send(user.toJSON());
};

Record Browser in your Controllers

const Company = use('App/Models/Company')
const JsonApiRB = use('JsonApiRecordBrowser');
const companies = await JsonApiRB
  .model(Company)
  .request(request.get()) //handle request
  .paginateOrFetch();
response.send(companies.toJSON());

The record browser supports:

Exceptions

You can use JsonApi to handle errors and be able to return valid JSON Api error responses. Create a global ehandler using adonis make:ehandler and use JsonApi in handle() function. See examples/Exception/Handler.js

async handle(error, options) {
    JsonApi.handleError(error, options);
}

Validator

Sample Validator (see examples)


const {formatters} = use('Validator');
const JsonApi = use('JsonApi');
class UserValidator {
get rules(){
return {
'username': 'required|accepted|max:255',
'contact_number': 'required|accepted|max:50',
'email': 'required|email|unique:companies,email|max:100'
}
}
get formatter() {
    return formatters.JsonApi;
}

async fails({errors}) {
    for (const error of errors) {
        const jsonError = JsonApi.JSE.UnprocessableResourceObject.invoke();
        jsonError.detail = error.detail;
        jsonError.source = error.source;
        JsonApi.pushError(jsonError);
    }
    return this.ctx.response
        .status(JsonApi.getJsonErrorStatus())
        .send(JsonApi.getJsonError());
}

}


#### Serializer Library:
> [Serializer functions](https://github.com/danivek/json-api-serializer/blob/master/lib/JSONAPISerializer.js)
``` javascript
const {JsonApiSerializer} = use('JsonApi');
const user = await User.find(1);
JsonApiSerializer.serialize("user", user);