npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rest-api-builder

v1.1.2

Published

Simple, flexible, scalable JavaScript client for communicating with RESTful resources.

Downloads

158

Readme

npm coverage

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

Install with npm or yarn.

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 is true.

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 resource
  • endpoints: (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 actions 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