1.0.10 • Published 4 months ago

interface-norel v1.0.10

Weekly downloads
-
License
ISC
Repository
-
Last release
4 months ago

documentation

interface is a toolchain for building JSON:API-compliant APIs.

what is JSON:API

If you’ve ever argued with your team about the way your JSON responses should be formatted, JSON:API can help you stop the bikeshedding and focus on what matters: your application.

By following shared conventions, you can increase productivity, take advantage of generalized tooling and best practices. Clients built around JSON:API are able to take advantage of its features around efficiently caching responses, sometimes eliminating network requests entirely.

read more

interface provides the following features:

  • generating API controllers from resources definitions.
  • generating authentication handlers from authentication schemes definitions.
  • generating OpenAPI definition and documentation for the API with schemas for request bodies and responses.
  • generating ExpressJS router.
  • generating clients with support to different target languages (see supported).
  • API testing.
  • API versioning.

building an API with interface consists of the following:

  • defining API resources using a dialect of JSON schema.
  • implementing datasources.
  • defining authentication schemes.

resources, authentication schemes and datasources are the trinity on top of which an interface API is built.

creating an interface project

$> npx interface be [--starter <starter>] <name>
  • : name of the interface project.
  • : specifying a starter project instead of starting from scratch, defaulting to starter “default”

interface project directory structure

  • resources: contains resource definitions.
  • datasource: contains datasource implementations.
  • controllers: where generated controllers reside.
  • authentication:
    • schemes: contains authentication scheme definitions.
    • handlers: where generated authentication handlers reside.
  • index.js: api entrypoint.
  • interface.configuration.json: contains interface configuration.
  • interface.openapi.json: contains API OpenAPI definition of the interface API.
  • package.json: contains dependencies and useful scripts.

defining API resources

according to JSON:API, a resource object consists of the following:

  • id
  • type
  • attributes
  • relationships

see Resource Objects.

interface uses JSON Schema capabilities to define resources.

to create a resource, run the following command substituting:

  • with the resource type (e.g. user, post, comment)
  • with the resource datasource (e.g. database, firebase, redis)
$> npx interface create resource <name> <datasource>
  • usage

implementing API datasources

a datasource is a set of functions that executes CRUD logic for each resource, interface relies on the datasources to read/write resources and resource relationships.

$> npx interface create datasource <name>
  • usage

when creating a datasource, it will be added to the datasources folder, it looks like this

module.exports = {
  name: "database",
  /**
   * create
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} attributes 
   * @param {*} relationships 
   * @param {*} options 
   */
  async create(identity, resource, attributes, relationships, options) {},
  /**
   * readOne
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} options 
   */
  async readOne(identity, resource, id, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} options 
   */
  async readMany(identity, resource, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} attributes 
   * @param {*} relationships 
   * @param {*} options 
   */
  async update(identity, resource, id, attributes, relationships, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} options 
   */
  async delete(identity, resource, id, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} relationship 
   * @param {*} value 
   * @param {*} options 
   */
  async createRelationships(identity, resource, id, relationship, value, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} relationship 
   * @param {*} value 
   * @param {*} options 
   */
  async updateToOneRelationship(identity, resource, id, relationship, value, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} relationship 
   * @param {*} value 
   * @param {*} options 
   */
  async updateToManyRelationship(identity, resource, id, relationship, value, options) {},
  /**
   * 
   * @param {*} identity 
   * @param {*} resource 
   * @param {*} id 
   * @param {*} relationship 
   * @param {*} value 
   * @param {*} options 
   */
  async deleteRelationships(identity, resource, id, relationship, value, options) {},
}

the datasource exposed functions are loaded by interface in the controllers and serializers to CRUD the data when need be. interface takes care of parsing request bodies, path and query parameters for inclusion of related resource, sparse fieldsets, filtering, sorting and pagination and passing them as arguments to the datasource functions.

defining authentication schemes

interface supports all authentication schemes defined in the OpenAPI specification (see security schemes).

$> npx interface create authentication <identifier>
  • usage

when an authentication scheme is defined, it’s added to the authentication/schemes directory. the available defined authentication schemes are added to the API OpenAPI definition.

generating API OpenAPI definition

interface allows you to generate an OpenAPI definition for your API.

$> npx interface generate definition
  • usage

the command will create the file .openapi.json containing the OpenAPI definition, where is the name of the interface project.

generating controllers

$> npx interface generate controllers [resource]
  • usage

the command generates controllers for all the endpoints in the controllers directory.

generating authentication handlers

$> npx interface generate authentication [authentication]
  • usage

the command generates authentication handlers in the authentication/handlers directory.

generating API client

$> npx interface generate client [--target <target>] [--output <output]
  • usage

the command generates client code to interact with the API.

running and testing the API

after defining your resources, creating your datasources and defining your authentication schemes, you are ready to run and start testing your API to continue with the implementation.

$> npx interface generate
  • usage

the generate command performs all the necessary generations (OpenAPI definition, controllers, authentication handlers, client). once generation is done, you can start listening and responding to requests.

const interface = require("interface");

const api = require("express")();

api.use(interface.router());

api.listen(process.env.PORT, () => {
  console.log(`api listening on port ${process.env.PORT}`);
});

in the above snippet, we are using the ExpressJS router that interface provides to us. the returned router looks into the generated OpenAPI definition and loads controllers for each endpoint, taking into consideration:

  • deserialization of requests.
  • validation of requests.
  • dependency injection of serializer, resource definition and datasource implementation, so that they are available to subsequent middlewares.
  • loading the controller.
  • serialization of responses.
  • error handling.

API versioning

an API is not necessarily a still artifact, resource definitions can be altered or removed to accomodate changes in business logic and so applies to datasources and authentication schemes. thus, we need to have means to version our API, which is two folds:

  • handling codebase breaking changes.
  • communicating API version with the client.

handling codebase breaking changes

API versioning makes sense for breaking changes, a breaking change is defined as:

  • removing a resource.
  • removing a resource’s attribute.
  • making a resource’s attribute required.
  • removing a resource’s relationship.

interface can detect breaking changes.

to list breaking changes run:

$> npx interface change status

to incorporate the list of breaking changes into a new version, run:

$> npx interface change apply

the command creates a new entry in the versions directory, when receiving requests, interface router takes care of dispatching the request to the controller in the corresponding version.

communicating API version with the client

configuration

the interface.configuration.json file is used to set project-wide configuration.

keydescription
serverslist of OpenAPI servers objects that will be injected in the generated OpenAPI definition.
paginationpagination configuration.
pagination.strategysetting pagination strategy.
versioningversioning configuration.
versioning.strategysetting versioning strategy.