rest-api-builder
v1.1.2
Published
Simple, flexible, scalable JavaScript client for communicating with RESTful resources.
Downloads
158
Readme
rest-api-builder
Simple, flexible, scalable JavaScript client for communicating with RESTful resources.
Features
- Auto-creates routes for standard REST endpoints
- Built-in parameter validation
- Request library agnostic
- Custom route schema definitions
- Single dependency (path-to-regexp)
Purpose
This project aims to reduce the boilerplate code for interacting with RESTful server-side resources. If you're familiar with the following setup, this library is for you.
import request from 'my-request-library'
const api = {
foo: {
list: () => {
return request({ method: 'get', url: '/foo/' })
},
retrieve: id => {
return request({ method: 'get', url: `/foo/${id}/` })
},
create: data => {
return request({ method: 'post', url: '/foo/', data })
},
update: (id, data) => {
return request({ method: 'put', url: `/foo/${id}/`, data })
},
destroy: id => {
return request({ method: 'delete', url: `/foo/${id}/` })
}
}
}
export default api
Install
npm install rest-api-builder
yarn add rest-api-builder
Usage
Create a new instance of the builder. Configuration options will be shared by all routes.
import request from 'my-request-library'
import RestAPIBuilder from 'rest-api-builder'
const config = {
requestFn: request,
baseURL: '',
appendSlash: true
}
export const builder = new RestAPIBuilder(config)
Builder Config
These are the available config options for the builder. Only requestFn
is required.
requestFn
: (required) Function that will be called when you use the routes generated by the builder. Returns a promise.baseURL
: (optional) Value will be prepended to each path generated by the builder.appendSlash
: (optional) If set,/
will be appended to each path. Default istrue
.
requestFn
requestFn
should wrap your request library and accept a single parameter, the config
object. Here's an example with the popular axios library:
import axios from 'axios'
import RestAPIBuilder from 'rest-api-builder'
const builder = new RestAPIBuilder({
requestFn: config => {
return axios(config)
}
})
Request Config
Here's a list of the requestFn
config options.
{
// server url
url: '/foo',
// http method
method: 'get',
// data to be sent as the request body
// only valid for POST, PUT, PATCH
data: {
foo: 'bar'
},
// any additional properties you'd like to pass to
// your request library, eg. url parameters
...{
params: {
q: 'foo'
}
}
}
Most http clients will have a similar api for making requests, so it should be pretty easy to transform these values to meet your needs.
Route building
Use the builder to generate api endpoints using create()
, which accepts
two parameters:
path
: (required) Path to the api resourceendpoints
: (optional) An array of endpoint objects
import { builder } from 'path/to/builder'
const resource = builder.create({
path: 'foo',
endpoints: [
{ action: 'list' },
{ action: 'retrieve' },
{ action: 'create' },
{ action: 'update' }
]
})
This results in the following schema, where action
becomes the invocation method name.
{
list: ([config]) => { ... }, // GET /foo
retrieve: (id[, config]) => { ... }, // GET /foo/:id
create: (id, data[, config]) => { ... }, // POST /foo
update: (id, data[, config]) => { ... } // PUT /foo/:id
}
If the endpoints
param is omitted, the following defaults will be created for you:
| Action | HTTP Method | Path |
| ------------- | ----------- | ---------- |
| list | GET | /foo
|
| retrieve | GET | /foo/:id
|
| create | POST | /foo
|
| update | PUT | /foo/:id
|
| partialUpdate | PATCH | /foo/:id
|
| destroy | DELETE | /foo/:id
|
Alternatively, you can create custom endpoints by providing an endpoint schema as follows.
{
action: String, // invocation method name
method: String, // http verb
path: String // custom route path
}
(Note: the default route action
s are reserved; if you use one in a custom endpoint
configuration the other params will be ignored and the standard REST endpoint will
be created instead.)
Endpoint definitions can be mixed. For example, if you want to create default endpoints for fetching data in addition to a custom route:
const resource = builder.create({
path: 'foo',
endpoints: [
{ action: 'list' },
{ action: 'retrieve' },
{ action: 'custom', method: 'put', path: 'bar/:id' }
]
})
It will create a schema that looks like this:
{
list: ([config]) = { ... }, // GET /foo
retrieve: (id[, config]) => { ... } // GET /foo/:id
custom: (id[, config]) => { ... } // PUT /foo/bar/:id
}
Named segments begin with :
. If the custom route contains
a named segment, id
will become a required field.
Multiple named segments are supported within a single endpoint path
.
const resource = builder.create({
path: 'foo',
endpoints: [
{ action: 'custom', method: 'get', path: 'bar/:p1/baz/:p2' }
]
})
When using multiple named segments, the id
argument becomes
an object instead of a primitive. Each segment should map to a
key in this object.
resource.custom({ p1: 'user', p2: 5 }) // PUT /foo/bar/user/baz/5
Invocation
Once the api schema has been created, you can import it and use as needed.
// src/services/api/users.js
import { builder } from './builder.js'
export const UserAPI = builder.create({
path: 'users',
endpoints: [
{ action: 'list' },
{ action: 'retrieve' },
{ action: 'create' }
]
})
// src/views/someView.js
import { UserAPI } from 'src/services/api/users.js'
async function listUsers () {
const response = await UserAPI.users.list()
}
async function retrieveUser(userId) {
const response = await UserAPI.users.retrieve(userId)
}
async function createUser() {
const payload = { username: 'Foo', email: '[email protected]' }
const response = await UserAPI.users.create(payload)
}
The invocation method signature will be different depending on its usage.
Routes which require a resource identifier (id)
resource.actionWithId(id[, data, config])
An id wil be required for retrieve
, update
, partialUpdate
,
destroy
, or if a custom action is used which contains at least
one named segment in the path
. If multiple named segments are
defined, this argument should be an object whose keys map to each
segment.
const resource = builder.create({
path: 'users',
endpoints: [
{ action: 'retrieve' },
{ action: 'custom', method: 'get', path: 'bar/:p1/baz/:p2' }
]
})
resource.retrieve(4)
resource.custom({ p1: 'user', p2: 5 })
Routes which require a request payload (data)
resource.actionWithData([id, ]data[, config])
A payload will be required for post
, put
, and patch
.
const resource = builder.create({
path: 'users',
endpoints: [
{ action: 'create' },
{ action: 'update' }
]
})
resource.create({ foo: 'bar' })
resource.update(4, { foo: 'bar' })
Validation
The builder will handle basic parameter validation for the following:
- Routes which target a specific resource
- Routes which require a payload (
post
,put
,patch
)
const resource = builder.create({
path: 'foo',
endpoints: [
{ action: 'custom', method: 'put', path: 'bar/:id' }
]
})
resource.custom() // throws MissingIdError
resource.custom(5) // throws MissingPayloadError
resource.custom(5, {}) // works
Development
You'll need node.js installed.
To get started, clone the repo:
git clone https://github.com/CBMasri/rest-api-builder.git
cd rest-api-builder
Commands:
npm run test # run tests
npm run test:coverage # generate coverage report
npm run build # build for production using webpack
Similar libraries
- https://github.com/Flyrell/rest-api-url-builder
- https://github.com/marmelab/restful.js
- https://github.com/robsontenorio/vue-api-query