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

gangplank

v0.1.2

Published

Robust, unopinionated, spec-driven validation for Swagger and Express APIs

Downloads

8

Readme

travis npm npm

Gangplank

Robust, unopinionated, spec-driven validation for Swagger and Express APIs

  • Robust: Heavily tested to support Swagger (aka OpenAPI) v2.0
  • Unopinionated: Works as an Express middleware without forcing any particular code patterns or error message formats.
  • Spec-driven: Facilitates rigorously defining an API spec once in a machine readable format, and then using that spec to perform all validation without needing to hand-write or generate any more validation code.

Things that fall outside the scope of the project:

  • Code-gen functionality. There are already several fantastic tools for scaffolding ExpressJs projects, but with this project, we want to stick to just validation.
  • Features that don't derive from the Swagger Specification.

Quick Start

  1. Install using npm: npm install gangplank

  2. Add middleware:

    var spec = require('./swagger.json');
    app.use(gangplank.requests({ swaggerDefinition: spec }));
  3. Add error handler:

    // Gangplank's default error handler returns errors in a JSON API style schema
    // (See below more info)
    app.use(gangplank.errorHandler);

Everything put together:

var express = require('express');
var gangplank = require('gangplank');

var app = express();

var spec = require('./swagger.json');
app.use(gangplank.requests({ swaggerDefinition: spec }));

// TODO: register routes here

// Gangplank's default error handler returns errors in a JSON API style schema
// (See below more info)
app.use(gangplank.errorHandler);

app.listen(3000, function () {
	console.log(`listening on port 3000`);
});

Parameter Access

Gangplank provides access to validated, type-cast parameters on the request via req.gangplank.params. For example, an integer parameter passed via the query string is guarenteed to be a valid value and will be cast to a Number object. This precludes some of the most common boilerplate code in ExpressJS route handlers: guard clauses for validating and casting parameters. Additionally, all parameters from all sources (path, query, body, header, and/or forms) are included in this single object. Parameter values can still be retrieved from their original locations (eg. req.params, req.get() etc), but those values will be in their original string format.

Example swagger.json:

{
	"swagger": "2.0",
	"paths": {
		"/users/{id}/widgets": {
			"get": {
				"parameters": [
					{
						"name": "id",
						"in": "path",
						"type": "string",
						"required": true
					},
					{
						"name": "offset",
						"in": "query",
						"type": "integer",
						"required": false,
						"default": 100,
						"minimum": 1,
						"maximum": 1000
					},
					{
						"name": "limit",
						"in": "query",
						"type": "integer",
						"required": false,
						"default": 0,
						"minimum": 0
					}
				]
			}
		}
	}
}

The associated route handler is as simple as:

app.get('/users/:id/widgets', (req, res, next) => {
	const userId = req.gangplank.params.id;      // String
	const offset = req.gangplank.params.offset;  // Number
	const limit = req.gangplank.params.limit;    // Number

	// TODO: add logic here

	res.status(501).send();
});

In the above example, the value of userId is trivially just the string value from the path, but offset and limit will be Number objects guarenteed to be within the correct range. Also, because they are not required and have default values, if the consumer does not include them in the query string, offset and limit will contain their respective default values.

Note that while Gangplank will include the body parameter, body-parser or another similar middleware must be run before app.use(gangplank.requests(options)); in order for the body content to be accessible. If the body is not parsed, it will not be found and will likely fail validation due to a missing parameter.

Error handling

In the event that a request does not validate per swagger.json, the request validation middleware will pass an Array containing all errors to the next() function. Validation errors will occur for one of three reasons:

Route not found

The request verb and URI do not match an operation defined in the spec.

{
	"route": "/users/12345/billing-info",
	"notFound": true
}

Note that even if a route handler is added to the Express app, if the operation verb and path are not defined in swagger.json, Gangplank will consider the route to not exist. Conversely, if the an operation is defined in swagger.json but not in the Express app, Gangplank will not create an error object, and Express will handle it with its default missing route behavior.

Missing parameter

The request does not contain a parameter defined as required in the spec.

{
	"parameter": "id",
	"location": "path",
	"notFound": true
}

Bad parameter

A parameter is contained in the request, but does not meet the criteria in the spec.

{
	"parameter": "id",
	"errors": []
}

The Swagger 2.0 specification is largely based on JSON Schema v4, and Gangplank relies heavily on the jsonschema package under the hood to perform validation. Because of this, the errors property in a Bad Parameter error is simply a collection of errors returned from the json schema validator.

Default Error Handler

By default, Gangplank is very unopinionated in how validation errors are handled. Errors are passed as an array via the next() function which allows developers to implement error handling in their preferred idiomatic Express style. However, for convenience, Gangplank includes an error handling middleware that converts the Gangplank error objects to the JSON API Error format:

app.use(gangplank.errorHandler);

Response validation

Validation of response messages is on the road map for this project, but has not yet been implemented.

Contributing

See our Contributing Guidelines