/unity-api

REST-API helper, wrapped around fetch

Primary LanguageJavaScript

Unity API

Travis-CI Coverage Status npm version Scrutinizer Deps Deps-Dev Dependency Status

REST-API helper, wrapped around fetch.

Table of Contents

Installation

npm i --save unity-api

API

createAPI(resources, middleware, namespace, cancelNamespace);

Returns: {Object}

Use module's default export to create an API object.

resources {Object} Optional

An API would be redundant without any of resources defined.

Each resource represents an entity in your REST-API as an object with the following properties:

namespace {String} Optional

Namespace of an entity. e.g.: example.com/api/user/get

methods {Object}

Dictionary of facade-methods that transform your api calls params to fetch calls params. Each method should return a plain object with the following properties:

path {Array|String} Optional

Default: ''

If path is an array, items will be joined and normalized.

query {Object} Optional

Default: {}

Query-like object.

options {Object} Optional

Default: {}

fetch options.

type {string} Optional

Default: 'json'

Alias: method

Type of reponse data / method to be called on fetch's response (ex: 'json', 'text', 'blob')

headers {Object|Headers}

Additional headers to be sent to the server

body {string|FormData}

Requests's body

Alternatively you can use provided shortcuts for every HTTP method

Example:

import { GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH } from 'unity-api';

const userResource = {
  namespace: 'user',

  methods: {
    // id = 1, extanted = true
    // GET: /api/user/1?extended=true
    get: ({ id, extended }) => ({ path: [id], query: { extended: !!extended } }),

    // POST: /api/user/1/edit
    save: ({ id, firstname, lastname }) => {
        const formData = new FormData();

        formData.append('firstname', firstname);
        formData.append('lastname', lastname);

        return POST({
            path: [id, 'edit'],
            headers: { 'x-csrf-token': 'blah' }
            body: formData
        });
    },

    // DELETE: /api/user/1
    delete: ({ id }) => DELETE({ path: [id] })
  }
}

middleware {Array} of {Function} Optional

An array of middleware functions, that can manipulate an api call, its params and its result, along with options for the remaning middleware in chain.

const myMiddleware = next => async (options, params, resource, method) => { return await next() }

next {Function}

An async function, that calls next middleware in chain, or, in case of last middleware, the api method itself.

options {Object} Optional

Middleware parameters, that an api call was made with.

params {Object} Optional

Parameters, that an api call was made with.

resource {String} Optional

Name of the resource, whose method was called.

method {String} Optional

Name of the method called

Example logger middleware:

export default next => async (middlewareOptions, apiCallParams, resource, method) => {
    console.log('args', { middlewareOptions, apiCallParams, resource, method }); // eslint-disable-line no-console
    const result = await next();
    console.log('result', result); // eslint-disable-line no-console
    return result;
};

namespace {String} Optional

Default: 'api'

Usually you would want to proxy api calls from the SPA to the backend using some common namespace. e.g. example.com/api/user/get

cancelNamespace {String} Optional

Default: 'cancel'

const promise = API.example.get();

promise.cancel();

Usually you would want to cancel api calls. This is the name of the cancel method.

Usage

You can call your API methods like so: API[resource][method](methodParams, middlewareOptions)

Example

Create API module:

// api.js
import createAPI from 'unity-api';

const resources = {
  user: {
    namespace: 'user',
    methods: {
      get: ({ id }) => ({ path: id }),
      delete: ({ id }) => ({ path: id, options: { method: 'DELETE' } }),
      getAsText: ({ id }) => ({ path: id, type: 'text' }),
    }
  }
}

const logger = next => async (middlewareOptions, apiCallParams, resource, method) => {
    const { log } = middlewareOptions;
    
    if (log) {
       console.log('args', { middlewareOptions, apiCallParams, resource, method }); // eslint-disable-line no-console
    }
    
    const result = await next();
    
    if (log) {
       console.log('result', result); // eslint-disable-line no-console
    }
    
    return result;
};

const middleware = [
  logger
]

const API = createAPI(resources, middleware, 'api', 'cancel');

export default API;

Use it in your application:

// index.js
import API from './api';

const user = await API.user.get({ id: 1 }, { log: true });

Contributing

  • Provide conventional commit messages by using npm run commit instead of git commit.
  • Core contributors: use GitHub's Rebase and merge as a default way of merging PRs.

License

MIT © AuRu