Package Exports
- openapi-routing
- openapi-routing/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (openapi-routing) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Schema-first microservice with OpenAPI 3
The openapi-routing library is a minimalistic solution to create a microservice from an OpenAPI schema.
OpenAPI schema is treated as ultimate single source of truth by describing and declaring interface / contract of our microservice. From this contract are derived all the routing rules that call appropriate handling functions - the behavior/functionality of the microservice.
The openapi-routing
library serves as a lightweight routing specified by Open API 3 in Node.js. This library does not need Express or any other framework, it uses just standard vanila JavaScript, and Node.js. But of course it coexists seamlesly with any framework, if the microservice uses framework's functionality.
A microservice with openapi-routing
is made in 2 steps:
- Designing OpenAPI schema for the API / microservice interface
- Writing handler modules and functions declared in the schema
Quick impression
- Clone
openapi-routing
to your local machine with commandgit clone https://github.com/tomi-vanek/openapi-routing.git
- Load dependencies with command
npm install
- Run example server with
node ./example-server/server.js
- Test in browser with URL
http://localhost:3333/v1/artists/foo-bar?x=123&aaa=qwerty
Create your own microservice from OpenAPI schema
- Create a new schema for the new REST API / microservice (for exploration purposes you may copy the
example-server/simple-api.yaml
schema) - Create a directory for your new REST microservice and go to that directory
- Initialize the microservice project with
npm init
. Project configuration filepackage.json
is created. - Add to the
package.json
configuration file following line to switch module loading to standard EcmaScript module system:"type": "module",
- Install and load the
openapi-routing
library with commandnpm i openapi-routing
- Create directory for request handlers - i.e.
handlers
and the handler modules (for exploration you may copy the directoryexample-server/handlers
into your project) - Create API server start module
server.js
(for exploration you may take the fileexample-server/server.js
)
How it works
The openapi-routing
library can be used in plain Node.js http / https createServer - no need to include additional framework (i.e. Express) to run a lightweight API server.
Server start
- By server start the
openapi-routing
reads Open API 3 schema for the REST service, either in YAML or in JSON format. - The
openapi-routing
identifies the paths from schema, and for each path the methods served in that path. - For each path and method is created a routing rule. Path is mapped to a JavaScript path and file in
<project-root-dir>/handlers
directory. Each HTTP method for the path in schema has a handler function exported in the ES6 handler module.
HTTP request handling
- By each HTTP request from a client, the
openapi-routing
finds the routing rule for incoming URL path and HTTP method. - The
openapi-routing
reads From the routing rule the file path to the handler module, and the name of the handler function in the module. - The
openapi-routing
opens the handler module, and calls asynchronously the handler function with incomming parameters and if appropriate, also with data from request body (i.e. by POST request). After the handler function finishes the processing, the return value is sent as HTTP response to the calling client.
Handlers - application logic
Application logic is organized into handler modules and implemented in handler functions.
Handler modules export handler functions that are called by routing logic to process API requests.
Handler modules are by convention in directory <project-root-dir>/handlers
. Each handler module path and name is identical with the http or https path in OpenApi schema that receives .js
extension.
Example:
- The path
/artists
has handler module<project-root-dir>/handlers/artists.js
. - The path
/artists/{username}
has handler module<project-root-dir>/handlers/artists/{username}.js
... curly brackets are valid characters in file name ;-).
Each handler module serves specific path defined in the OpenAPI schema. Handler module is a regular ES6 module (defined in JavaScript standards and supported in current Node.js). For each HTTP method specified in the OpenAPI schema, the handler module exports a handler function. Name of the handler function is by convention handle<METHOD>
- i.e. handleGet(parameters)
, handlePost(parameters, data)
. HTTP methods are GET, POST, PUT, PATCH, DELETE, HEAD, etc.
Router reads parameters from URL path and from query. Parameters are merged to parameters object. If the request provides also data in body (in JSON format), the router reads incomming data, concatenates them (supporting multipart - data in more calls from client), and provides these parameters and data to handler function.
Handler function is defined as async
, so if processing is long, it does not block the server by executing handlers for concurrent requests in parallel. Handler function returns data that will be sent to client either directly in text format or and object that is going to be serialized to JSON format, or data in binary format together with the mime format definition.
Binary return value is an object with 2 fields:
- mime --> MIME type (IANA media type), i.e. "image/png"
- data --> buffer or stream with binary data
Example of a handler with simple return value (string object):
export async function handleGet(params) {
// parameter handling, create response data
// ... in this case for test we return params without any change
return params;
}
export async function handlePost(params, data) {
// parameter handling, create response data
// ... in this case for test we return input data without any change
return data;
}
Example of a handler with binary return value (string object):
import {promises as fsPromises} from 'fs';
const fileName = new URL('.', import.meta.url).pathname
+ '../assets/pie-chart.jpg';
export async function handleGet() {
return {
mime: 'image/jpg',
data: fsPromises.readFile(fileName),
};
}
Meta endpoints
Router offers endpoints that provide "technical" meta information about the API that are not declared in the schema:
/meta/schema.yaml
- provides schema in YAML format/meta/schema.json
- provides schema in JSON format/meta/health
- health check for simpler deployment to cloud environment/meta/info
- basic information about the service - extracted from the OpenAPI schema/meta/routing
- routing rules used for request handling
User interface
Very useful fearure for a microservice is web user interface generated form the OpenAPI schema. User interface can serve as human-readable documentation, as experimenting tool for developers or as a tool for testers.
Adding UI to your microservice is simple:
- Create directory with name
ui
in root of the microservice - Download the newest release of Swagger UI from page https://github.com/swagger-api/swagger-ui/releases
- Unzip the code, and copy hte content of the directory
release
into the directoryui
in your project - Edit the file
/ui/index.html
:
Change the schema URL to
"/meta/schema.yaml"
:const ui = SwaggerUIBundle({ url: "/meta/schema.yaml",
Optional: change the configuration of the UI application. I usually add following lines to the SwaggerUIBundle configuration object:
const ui = SwaggerUIBundle({ ... // custom configuration: tryItOutEnabled: true, jsonEditor: true, showRequestHeaders: true, defaultModelExpandDepth: 5, defaultModelsExpandDepth: 5, defaultModelRendering: "model", displayRequestDuration: true, docExpansion: "list", };
Optional: change the look & feel of the application - select a theme from https://ostranme.github.io/swagger-ui-themes/
Optional: change the logo, favicon, title in HTML, change fonts and colors with CSS, ... (the visual aesthetic is very important)
Roadmap
Ideas for enhancements in future releases of openapi-routing
:
- Configuration
- Compatibility with Express framework
- Plugable architecture for simple integration and for extensions --> processing cascade
- Headers for secure responses
- Support for compressed responses
- Code generator for initial structure of handlers and Dockerfile for simple deployment
Credits
- YAML reading and transformation to/from JSON: https://eemeli.org/yaml/
- Image in example was created from https://commons.wikimedia.org/wiki/File:Mammal_species_pie_chart.svg