Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/krakenjs/hapi-openapi
Build design-driven apis with OpenAPI (formerly swagger) 2.0 and hapi.
https://github.com/krakenjs/hapi-openapi
api hapi openapi rest swagger
Last synced: 5 days ago
JSON representation
Build design-driven apis with OpenAPI (formerly swagger) 2.0 and hapi.
- Host: GitHub
- URL: https://github.com/krakenjs/hapi-openapi
- Owner: krakenjs
- License: other
- Created: 2014-10-16T20:17:54.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2022-02-18T16:53:27.000Z (almost 3 years ago)
- Last Synced: 2024-12-19T01:09:16.061Z (7 days ago)
- Topics: api, hapi, openapi, rest, swagger
- Language: JavaScript
- Homepage:
- Size: 339 KB
- Stars: 211
- Watchers: 23
- Forks: 75
- Open Issues: 30
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# hapi-openapi
[![Build Status](https://travis-ci.org/krakenjs/hapi-openapi.svg?branch=master)](https://travis-ci.org/krakenjs/hapi-openapi)
[![NPM version](https://badge.fury.io/js/hapi-openapi.png)](http://badge.fury.io/js/hapi-openapi)### Note: this project was renamed from 'swaggerize-hapi' to 'hapi-openapi'.
`hapi-openapi` is a design-driven approach to building RESTful services with [OpenAPI (Swagger)](http://openapis.org) and [Hapi](http://hapijs.com).
`hapi-openapi` provides the following features:
- API schema validation.
- Routes based on the OpenAPI document.
- API documentation route.
- Input validation.### Why "Design Driven"
There are already a number of modules that help build RESTful APIs for node with OpenAPI. However,
these modules tend to focus on building the documentation or specification as a side effect of writing
the application business logic.`hapi-openapi` begins with the OpenAPI document first. This facilitates writing APIs that are easier to design, review, and test.
At runtime, `hapi-openapi` uses the API specification to build routes from previously defined paths. This ensures that everything specified is what is implemented.
### Quick Start with a Generator
This guide will let you go from an `api.json` to a service project in no time flat.
First install `generator-swaggerize` (and `yo` if you haven't already):
```bash
$ npm install -g yo
$ npm install -g generator-swaggerize
```Now run the generator.
```bash
$ mkdir petstore && cd $_
$ yo swaggerize
```Follow the prompts (note: make sure to choose `hapi` as your framework choice).
You now have a working api and can use something like [SwaggerHub](https://swaggerhub.com/?_ga=2.118604234.2143392684.1515431456-1673703125.1481054263) to explore it.
### Manual Usage
```javascript
const Hapi = require('@hapi/hapi');
const Path = require("path");const server = new Hapi.Server( { port: 3000 } );
async function init () {
await server.register({
plugin: require('hapi-openapi'),
options: {
api: Path.join(__dirname, './config/pets.json'),
handlers: Path.join(__dirname, './handlers')
}
});
await server.start();
console.log( server.info.uri );
}init();
```### Hapi Plugin
The plugin will be registered as `openapi` on `server.plugins` with the following exposed:
- `getApi()` - the resolved Swagger document.
- `setHost(host)` - a helper function for setting the `host` property on the `api`.### Configuration Options
- `api` - a path to a valid OpenAPI 2.0 document, or a valid document in the form of an object.
- *deprecated* `docspath` - the path to expose api docs for swagger-ui, etc. Defaults to `/api-docs`.
- `docs` - an object used to configure the api docs route.
- `path` - the path to expose api docs for swagger-ui, etc. Defaults to `/api-docs`.
- `auth` - options auth config for this route.
- `stripExtensions` - strip vendor extensions from docs. Defaults to true.
- `prefixBasePath` - prefix path of docs with he OpenAPI document's `basePath` value. Defaults to true.
- `handlers` - either a string directory structure for route handlers, object, or not set if using `x-hapi-handler`.
- `extensions` - an array of file extension types to use when scanning for handlers. Defaults to `['js']`.
- `vhost` - *optional* domain string (see [hapi route options](http://hapijs.com/api#route-options)).
- `cors` - *optional* cors setting (see [hapi route options](http://hapijs.com/api#route-options)).
- `outputvalidation` - *optional* validate response data.### Mount Path
Api `path` values will be prefixed with the OpenAPI document's `basePath` value. This behavior can be negated if you set the option `docs.prefixBasePath` to `false`.
### Handlers Directory
The `options.handlers` option specifies a directory to scan for handlers. These handlers are bound to the api `paths` defined in the OpenAPI document.
```
handlers
|--foo
| |--bar.js
|--foo.js
|--baz.js
```Will route as:
```
foo.js => /foo
foo/bar.js => /foo/bar
baz.js => /baz
```### Path Parameters
The file and directory names in the handlers directory can also represent path parameters.
For example, to represent the path `/users/{id}`:
```shell
handlers
|--users
| |--{id}.js
```This works with directory names as well:
```shell
handlers
|--users
| |--{id}.js
| |--{id}
| |--foo.js
```To represent `/users/{id}/foo`.
### Handlers File
Each provided javascript file should export an object containing functions with HTTP verbs as keys.
Example:
```javascript
module.exports = {
get: function (req, h) { ... },
put: function (req, h) { ... },
...
}
```Optionally, `pre` handlers can be used by providing an array of handlers for a method:
```javascript
module.exports = {
get: [
function p1(req, h) { ... },
function handler(req, h) { ... }
],
}
```### Handlers Object
The directory generation will yield this object, but it can be provided directly as `options.handlers`.
Example:
```javascript
{
'foo': {
'get': function (req, h) { ... },
'bar': {
'get': function (req, h) { ... },
'post': function (req, h) { ... }
}
}
...
}
```### X-Hapi-Handler
Alternatively the API document can set `x-hapi-handler` attribute on each defined `paths` element if `handlers` is not defined.
Example:
```
"/pets/{id}": {
"x-hapi-handler": "./routes/pets-by-id.js",
.
.
.
```This will construct a `handlers` object from the given `x-hapi-handler` files.
### X-Hapi-Options
There is now support at the operations level for `x-hapi-options` which represent individual [Hapi Route Optijons](https://github.com/hapijs/hapi/blob/master/API.md#route-options).
This support is limited to configuration supported by the JSON file type.
Example:
```
"/internal": {
"post": {
"x-hapi-options": {
"isInternal": true
}
.
.
.
```### Authentication
Support for OpenAPI [security schemes](http://swagger.io/specification/#securitySchemeObject) requires that relevant authentication scheme and strategy are registered before the hapi-openapi plugin. See the [hapi docs](http://hapijs.com/tutorials/auth) for information about authentication schemes and strategies.
The name of the hapi authentication strategy is expected to match the name field of the OpenAPI [security requirement object](http://swagger.io/specification/#securityRequirementObject).
Example:
```yaml
securityDefinitions:
api_key:
type: apiKey
name: Authorization
in: header
paths:
'/users/':
get:
security:
- api_key: []
``````javascript
const server = new Hapi.Server();await server.register({ plugin: AuthTokenScheme });
server.auth.strategy('api_key', 'auth-token-scheme', {
validateFunc: async function (token) {
// Implement validation here, return { credentials, artifacts }.
}
});await server.register({
plugin: require('hapi-openapi'),
options: {
api: require('./config/pets.json'),
handlers: Path.join(__dirname, './handlers')
}
});
```### X-Hapi-Auth
Alternatively it may be easier to automatically register a plugin to handle registering the necessary schemes and strategies.
**x-hapi-auth-schemes**
The root document can contain an `x-hapi-auth-schemes` object specifying different plugins responsible for registering auth schemes.
Example:
```
"x-hapi-auth-schemes": {
"apiKey": "../lib/xauth-scheme.js"
}
```This plugin will be passed the following options:
- `name` - the auth scheme name, in this example `apiKey`.
**x-hapi-auth-strategy**
The `securityDefinitions` entries can contain an `x-hapi-auth-strategy` attribute pointing to a plugin responsible for registering auth strategies.
Example:
```
"securityDefinitions": {
"api_key": {
"x-hapi-auth-strategy": "../lib/xauth-strategy.js",
"type": "apiKey",
"name": "authorization",
"in": "header"
}
}
```The plugin will be passed the following options:
- `name` - the `securityDefinitions` entry's key. In this example, `api_key`. This is typically used as the strategy name.
- `scheme` - the `securityDefinitions` `type`. In this example, `apiKey`. This should match a `x-hapi-auth-scheme` name.
- `where` - `securityDefinitions` entry `in` attribute. This is search for the `lookup` value; in this example `header`.
- `lookup` - `securityDefinitions` entry `name` attribute. Used as the name to look up against `where`.The way you can make these play together is that for every `type`, a scheme exists that delegates some lookup or evaluation to the appropriate strategy.
Example:
```javascript
//xauth-scheme.jsconst register = function (server, { name }) {
server.auth.scheme(name /*apiKey*/, (server, /* options received from the strategy */ { validate }) => {
return {
authenticate: async function (request, h) {
return h.authenticated(await validate(request));
}
};
});
};module.exports = { register, name: 'x-hapi-auth-scheme' };
```and
```javascript
//xauth-strategy.jsconst Boom = require('@hapi/boom');
const register = function (server, { name, scheme, where, lookup }) {
server.auth.strategy(name, /* the scheme to use this strategy with */ scheme, {
//Define a validate function for the scheme above to receive
validate: async function (request) {
const token = request.headers[lookup];//Some arbitrary example
if (token === '12345') {
return { credentials: { scope: ['read'] }, artifacts: { token } };
}throw Boom.unauthorized();
}
});
};module.exports = { register, name: 'x-hapi-auth-strategy' };
```