Skip to content

PAPI: Builder🔗

PAPI allows API endpoints to be defined as simply or robustly as needed. An expanded example of the JSONPlaceholder API's /albums endpoint is demonstrated below:

Albums endpoint from JSONPlaceholder

import { papi } from '@studiokeywi/papi';

const albumShape/* (1)! */ = { userId: 0/* (2)! */, id: 0, title: '' };
const errShape = {};
const photoShape = { albumId: 0, id: 0, title: '', url: '', thumbnailUrl: '' };

const apiCaller = papi('https://jsonplaceholder.typicode.com')
  .path/* (3)! */('albums', $albums =>
    $albums
      .get/* (4)! */([albumShape], $get => $get.error/* (5)! */(errShape).queryOpt(albumShape))
      .post(albumShape, $post => $post.bodyOpt(albumShape).error(errShape))
      .slug/* (6)! */($albumId =>
        $albumId
          .get(albumShape, $get => $get.error(errShape))
          .delete({}, $del => $del.error(errShape))
          .patch(albumShape, $patch => $patch.bodyOpt(albumShape).error(errShape))
          .put(albumShape, $put => $put.bodyOpt(albumShape).error(errShape))
          .path('photos', $photos => $photos.get([photoShape], $get => $get.error(errShape)))
      )
  )
  .build();
  1. Commonly used shapes can be defined ahead of time if desired. See the specifity of responses section of the notes for more on response shapes
  2. PAPI infers the types inside an object, so placeholders like 0 and '' work
  3. Nested routes are defined with builder functions inside of .path()
  4. Endpoint functions provide shapes for the response type, and optional builder functions to modify how to interact with the endpoint/how it responds. PAPI supports DELETE, GET, PATCH, POST, and PUT
  5. Endpoint builder functions can clarify how interacitons with an API work when passing data (as a body or via query parameters) and with known error shapes
  6. Paths that are used as slugs for values are defined with .slug()

papi🔗

The papi function takes two arguments; the first is a string representing the base URL for an API, and the second is an optional shape used as the base shape of the builder. The second argument primarily used for internally updating the state of the builder, but is exposed for advanced/edge use cases as well as for possible feature enhancements in the future

Tip

See the composing builders and declarative building sections of the notes for more on advanced usage of the papi function

General Functions🔗

The .build function is used to create an API Caller tool for calling API endpoints. It accepts a single optional argument providing configuration to the built API Caller

Tip

The following configuration options are available:

Automatically attach Bearer [apiKey] values to the Authorization header

Warning

As a reminder, PAPI does not enforce or guarantee response shapes. It is intended as an augment to developer experience

Convert the API caller tool into a temporary API caller

See the TAPI section of the notes for more information

API docs: .build

The .path function defines a subpath for the current level of the builder. Typically, the top level of a builder will include nothing but paths, and paths may be nested arbitrarily deep. It accepts two arguments; The first is a string of the path segment, and the second is a nested builder which is used to define the shape of the path

API docs: .path

The .shared function defines multiple subpaths for the current level of the builder. This is similar to a .slug except where the values are known ahead of time instead of arbitrary values. It accepts two arguments; The first is an array of strings representing each path segment, and the second is a nested builder which is used to define the shape of each path

API docs: .shared

The .slug function defines a subpath where the actual pathname is not fixed but may be replaced by a given value. Typically this is seen with ID values representing a path segment as opposed to using a query parameter to provide the ID. It accepts a single argument, which is a nested builder that defines the shape of the path represented by the slug value

API docs: .slug

Endpoint Functions🔗

The following functions follow a similar pattern and are used for defining endpoint responses:

The .delete function defines the shape of the responses from calling an endpoint with an HTTP DELETE request. It accepts two arguments; The first is the shape of the response from the API, and the second is an optional endpoint builder that customizes the behavior of requesting/shape of responses from the API

API docs: .delete

The .get function defines the shape of the responses from calling an endpoint with an HTTP GET request. It accepts two arguments; The first is the shape of the response from the API, and the second is an optional endpoint builder that customizes the behavior of requesting/shape of responses from the API

API docs: .get

The .patch function defines the shape of the responses from calling an endpoint with an HTTP PATCH request. It accepts two arguments; The first is the shape of the response from the API, and the second is an optional endpoint builder that customizes the behavior of requesting/shape of responses from the API

API docs: .patch

The .post function defines the shape of the responses from calling an endpoint with an HTTP POST request. It accepts two arguments; The first is the shape of the response from the API, and the second is an optional endpoint builder that customizes the behavior of requesting/shape of responses from the API

API docs: .post

The .put function defines the shape of the responses from calling an endpoint with an HTTP PUT request. It accepts two arguments; The first is the shape of the response from the API, and the second is an optional endpoint builder that customizes the behavior of requesting/shape of responses from the API

API docs: .put

Endpoint Builders🔗

The endpoint functions all can accept an optional endpoint builder function as the second argument. These can be used to provide more specific/nuanced information about how APIs should be called and the data they return:

The .bodyOpt function is used to declare that an endpoint can receive some body of data. It accepts two arguments, an object defining the shape of accepted data for the endpoint and an optional object defining the shape the API responds with when sending a body of data

API docs: .bodyOpt

The .bodyReq function is used to declare that an endpoint must receive some body of data. It accepts two arguments, an object defining the shape of accepted data for the endpoint and an optional object defining the shape the API responds with when sending a body of data

API docs: .bodyReq

The .error function defines the shape of the response for a given endpoint's error. When provided, the built API caller will return the union of the relevant response shape and the error shape to indicate that error responses must be handled. It accepts a single argument defining the shape of error responses

Tip

See the type narrowing section of the notes for more handling error response shapes

API docs: .error

The .queryOpt function defines query parameters that may be appended to an endpoint request. It accepts two arguments, an object defining the shape of query parameters that may be used when calling an endpoint, and an optional object defining the shape the API responds with when sending query parameters

API docs: .queryOpt

The .queryReq function defines query parameters that must be appended to an endpoint request. It accepts two arguments, an object defining the shape of query parameters that must be used when calling an endpoint, and an optional object defining the shape the API responds with when sending query parameters

API docs: .queryReq

Tip

See the response priority section of the notes to see how PAPI determines the shape of an API response when providing endpoint builders