Giter VIP home page Giter VIP logo

hapi-swaggered's Introduction

hapi-swaggered 3.x

Yet another hapi plugin providing swagger compliant API specifications (swagger specs 2.0) based on routes and joi schemas to be used with swagger-ui.

Supports hapi 17.x and up

For earlier versions check hapi-swaggered 2.x (current default/latest npm install hapi-swaggered --save)

Build Status Coverage Status js-standard-style npm downloads

Install

npm install hapi-swaggered@next --save

Similar swagger-projects for hapi

krakenjs/swaggerize-hapi follows a design driven approach (swagger-schema first) for building APIs. In other words: it supports you to implement an api behind a specific swagger-schema while you have to create and maintain the swagger-schema yourself (or a third-party). In contrast with hapi-swaggered you will have to design your api through hapi route defintions and joi schemas (or did already) and hapi-swaggered will generate it's swagger specifications up on that (Of course not as beautiful and shiny structured as done by hand). Based on this you are able to get beautiful hands-on swagger-ui documentation (like this) for your api up and running (e.g. through hapi-swaggered-ui).

Swagger-UI

This plugin does not include the swagger-ui interface. It just serves a bare swagger 2.0 compliant json feed. If you are looking for an easy swagger-ui plugin to drop-in? You should have a look at:

Plugin Configuration

  • requiredTags: an array of strings, only routes with all of the specified tags will be exposed, defaults to: ['api']
  • produces: an array of mime type strings, defaults to: [ 'application/json' ]
  • consumes: an array of mime type strings, defaults to: [ 'application/json' ]
  • endpoint: route path to the swagger specification, defaults to: '/swagger'
  • routeTags: an array of strings, all routes exposed by hapi-swaggered will be tagged as specified, defaults to ['swagger']
  • stripPrefix: a path prefix which should be stripped from the swagger specifications. E.g. your root resource are located under /api/v12345678/resource you might want to strip /api/v12345678, defaults to null
  • basePath: string, optional url base path (e.g. used to fix reverse proxy routes)
  • supportedMethods: array of http methods, only routes with mentioned methods will be exposed, in case of a wildcard * a route will be generated for each method, defaults to ['get', 'put', 'post', 'delete', 'patch']
  • host: string, overwrite requests host (e.g. domain.tld:1337)
  • schemes: array of allowed schemes e.g. ['http', 'https', 'ws', 'wss'] (optional)
  • info: exposed swagger api informations, defaults to null (optional)
    • title: string (required)
    • description: string (required)
    • termsOfService: string
    • contact: object (optional)
      • name: string
      • url: string
      • email: string
    • license: object (optional)
      • name: string: string
      • url: string: string
    • version: version string of your api, which will be exposed (required)
  • tagging: Options used for grouping routes
    • mode: string, can be path (routes will be grouped by its path) or tags (routes will be grouped by its tags), default is path
    • pathLevel integer, in case of mode path it defines on which level the path grouping will take place (default is 1)
    • stripRequiredTags boolean, in case of mode tags it defines if the requiredTags will not be exposed (default is true)
  • tags: object (or array with objects according to the swagger specs) for defining tag / group descriptions. E.g. you two endpoints /get/this and /get/that and the tagging mode is set to path (with pathLevel: 1) they will be groupped unter /get and you are able to define a description through this object as { 'get': 'get this and that' }, defaults to null
  • cors: boolean or object with cors configuration as according to the hapijs documentation (defaults to false)
  • cache: caching options for the swagger schema generation as specified in server.method() of hapi, defaults to: { expiresIn: 15 * 60 * 1000 }
  • responseValidation: boolean, turn response validation on and off for hapi-swaggered routes, defaults to false
  • auth: authentication configuration hapijs documentation (default to undefined)
  • securityDefinitions: security definitions according to [swagger specs](https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md]

Example

Example configuration for hapi-swaggered + hapi-swaggered-ui

const Hapi = require('hapi');

(async () => {
  const server = await new Hapi.Server({
    port: 8000
  })

  await server.register([
    require('inert'),
    require('vision'),
    {
      plugin: require('hapi-swaggered'),
      options: {
        tags: {
          'foobar/test': 'Example foobar description'
        },
        info: {
          title: 'Example API',
          description: 'Powered by node, hapi, joi, hapi-swaggered, hapi-swaggered-ui and swagger-ui',
          version: '1.0'
        }
      }
    },
    {
      plugin: require('hapi-swaggered-ui'),
      options: {
        title: 'Example API',
        path: '/docs',
        authorization: {
          field: 'apiKey',
          scope: 'query', // header works as well
          // valuePrefix: 'bearer '// prefix incase
          defaultValue: 'demoKey',
          placeholder: 'Enter your apiKey here'
        },
        swaggerOptions: {
          validatorUrl: null
        }
      }
    }
  ])

  server.route({
    path: '/',
    method: 'GET',
    handler (request, h) {
      return h.response().redirect('/docs')
    }
  })

  try {
    await server.start()
    console.log('Server running at:', server.info.uri)
  } catch (err) {
    console.log(err)
  }
})()

Demo Routes

server.route({
  path: '/foobar/test',
  method: 'GET',
  options: {
    tags: ['api'],
    description: 'My route description',
    notes: 'My route notes',
    handler () {
      return {};
    }
  }
});

server.route({
  path: '/foobar/{foo}/{bar}',
  method: 'GET',
  options: {
    tags: ['api'],
    validate: {
      params: {
        foo: Joi.string().required().description('test'),
        bar: Joi.string().required()
      }
    },
    handler () {
      return {};
    }
  }
});

Features

Model naming

To assign custom names to your Models use the Joi.meta() option (in previous joi versions Joi.options() may be used)

Joi.object({}).meta({ className: 'FooBar' });

Model description

To assign a description to your Models use the Joi.meta() option like above

Joi.object({}).meta({ description: 'A description of FooBar' });

Type naming

To override the type a Joi model should be interpreted as, use the Joi.meta() option like above. This is especially useful when utilizing the extend and coerce features of Joi schema definition

Joi.object({}).meta({ swaggerType: string });

Document responses

There are 2 and a half different ways of documenting responses of routes:

The hapi way:

{
  options: {
    response: {
      schema: Joi.object({
        bar: Joi.string().description('test').required()
      }).description('test'),
      status: {
        500: Joi.object({
          bar: Joi.string().description('test').required()
        })
      }
    }
  }
}

The plugin way without schemas:

{
  options: {
    plugins: {
      'hapi-swaggered': {
        responses: {
          default: {description: 'Bad Request'},
          500: {description: 'Internal Server Error'}
        }
      }
    },
    response: {
      schema: Joi.object({
        bar: Joi.string().required()
      }).description('test')
    }
  }
}

The plugin way with schemas:

{
  options: {
    plugins: {
      'hapi-swaggered': {
        responses: {
          default: {
            description: 'Bad Request', schema: Joi.object({
              bar: Joi.string().description('test').required()
            })
          },
          500: {description: 'Internal Server Error'}
        }
      }
    }
  }
}

Specify an operationId for a route:

{
  options: {
    plugins: {
      'hapi-swaggered': {
        operationId: 'testRoute'
      }
    }
  }
}

Specify an security options to a route / operation:

{
  options: {
    plugins: {
      'hapi-swaggered': {
        security: {}
      }
    }
  }
}

Tag filtering

Routes can be filtered for tags through the tags query parameter beside the requiredTags property which is always required to be present.

For example:

  • ?tags=public,beta (equal to ?tags=+public,+beta)
    • will only show apis and routes with tag public AND/OR beta.
  • ?tags=public,-beta (equal to ?tags=+public,-beta)
    • will only show apis and routes with tag public AND NOT beta.

Known issues

No response types

The routes response schemas which hapi-swaggered is parsing will be dropped by hapi whenever the response validation is disabled. In this case hapi-swaggered will not be able to show any response types. A very low sampling rate is sufficient to keep the repsonse types.

hapi-swaggered's People

Contributors

albertovasquez avatar danielkwinsor avatar felixheck avatar greenkeeperio-bot avatar kruzty avatar lroggendorff avatar mikesir87 avatar predic8 avatar roundaround avatar savardc avatar sberryman avatar tatort79 avatar z0mt3c avatar zachguo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

hapi-swaggered's Issues

Using Hapi 15.x multiple connections returned an error

I tried to build a project which divide into several connections which contains API on each connection, and expect to have API documentation for it.
And it's returned and error:

Error: Server method function name already exists: resources
which referencing to this code at L56

I have no idea if somebody has got the same idea and/or issue for this error.

My codes has more complex than below, it do the similar way like Glue does, which I don't use in this case.

Illustration in codes:

//-- I need to have more than one connections

//-- Registering new connection as "ONE" at 8080
server.connection({
  host: 'one.app.local.host',
  port: 8080,
  labels: 'one'
});

//-- Registering new connection as "TWO" at 8090
server.connection({
  host: 'two.app.local.host',
  port: 8090,
  labels: 'two'
});

//-- Registering Inert & Vision for both connections ( ONE and TWO )
server.register([
  require('inert'),
  require('vision')
], {
  select: [ 'one', 'two' ]
}, function(error){
  if (error) {
    throw error;
  }
});

//-- Registering Hapi-Swaggered & Hapi-Swaggered-UI to connection "ONE"
server.register([
  {
    register: require('hapi-swaggered'),
    options: {
      auth: false,
      basePath: '/',
      host: 'one.local.host:8080',
      schemes: ['http'],
      consumes: [ 'application/json' ],
      produces: [ 'application/json' ],
      requiredTags: [ 'one' ],
      responseValidation: true,
      info: {
        title: 'ONE API Documentation',
        description: 'API documentation for connection ONE',
        version: '1.0'
      }
    }
  },
  {
    register: require('hapi-swaggered-ui'),
    options: {
      title: 'ONE App',
      path: '/docs',
      auth: false,
      authorization: false,
    }
  }
], {
  select: [ 'one' ]
}, function (error) {
  if (error) {
    throw error;
  }
});

//-- Registering Hapi-Swaggered & Hapi-Swaggered-UI for connection TWO
server.register([
  {
    register: require('hapi-swaggered'),
    options: {
      auth: false,
      basePath: '/',
      host: 'two.local.host:8090',
      schemes: ['http'],
      consumes: [ 'application/json' ],
      produces: [ 'application/json' ],
      requiredTags: [ 'two' ],
      responseValidation: true,
      info: {
        title: 'TWO API Documentation',
        description: 'API documentation for connection TWO',
        version: '1.0'
      }
    }
  },
  {
    register: require('hapi-swaggered-ui'),
    options: {
      title: 'TWO App',
      path: '/docs',
      auth: false,
      authorization: false,
    }
  }
], {
  select: [ 'two' ]
}, function (error) {
  if (error) {
    throw error;
  }
});

Why I did register the both plugins twice?

It's because I need the plugins to apply for selected connections ( ONE and TWO ).
That's why I implement server.register twice, or might more if have more connections to have hapi-swaggered for documenting API on preferred connections.

Then it return these error:

Error: Server method function name already exists: resources
    at Object.exports.unique.exports.contain.exports.reachTemplate.exports.assert.condition [as assert] (/home/itsme/NodeApp/node_modules/hapi/node_modules/hoek/lib/index.js:736:11)
    at internals.Methods._add.normalized [as _add] (/home/itsme/NodeApp/node_modules/hapi/lib/methods.js:47:10)
    at internals.Methods.add (/home/itsme/NodeApp/node_modules/hapi/lib/methods.js:26:21)
    at module.exports.internals.Plugin.parent.auth.internals.Plugin.register.internals.Plugin.method (/home/itsme/NodeApp/node_modules/hapi/lib/plugin.js:540:31)

    at Object.module.exports.register.next (/home/itsme/NodeApp/node_modules/hapi-swaggered/lib/index.js:56:13)
    ~^^^~ here above.. I realized the error raised caused by registering hapi-method more than one for the same method name of "resources"

    at Object.target [as register] (/home/itsme/NodeApp/node_modules/hapi/node_modules/joi/lib/object.js:77:34)
    at each (/home/itsme/NodeApp/node_modules/hapi/lib/plugin.js:318:14)
    at iterate (/home/itsme/NodeApp/node_modules/hapi/node_modules/items/lib/index.js:36:13)
    at Object.exports.serial (/home/itsme/NodeApp/node_modules/hapi/node_modules/items/lib/index.js:39:9)
    at Object.module.exports.internals.Plugin.parent.auth.internals.Plugin.register.each [as register] (/home/itsme/NodeApp/node_modules/hapi/lib/plugin.js:321:11)
    at /home/itsme/NodeApp/lib/engine.js:866:28
    at iterate (/home/itsme/NodeApp/node_modules/hapi/node_modules/items/lib/index.js:36:13)
    at done (/home/itsme/NodeApp/node_modules/hapi/node_modules/items/lib/index.js:28:25)
    at Object.method (/home/itsme/NodeApp/services/www/configs/hapi-auth-jwt2.pluginmethod.js:101:4)
    at /home/itsme/NodeApp/lib/engine.js:869:26
    at /home/itsme/NodeApp/node_modules/hapi/node_modules/hoek/lib/index.js:854:22
    at nextTickCallbackWith0Args (node.js:452:9)
    at process._tickCallback (node.js:381:13)
    at Function.Module.runMain (module.js:449:11)
    at startup (node.js:139:18)
    at node.js:999:3
[ERROR] 11:38:23 Error

I realized the error raised caused by applying the Hapi server.method more than one for the same method name of resources.
Yeah.. I knew.. it's because I did register the plugins more than one.

I start to inspect directly to the code /lib/index.js L56

Then.. I done this way at L56 and the results comes perfectly as expected ! :)

    //-- Check if current "resources" method is already defined
    if (plugin.methods.resources === undefined) {
      plugin.method('resources', resourcesGenerator, {
        cache: settings.cache,
        generateKey: internals.keyGenerator
      })
      resourcesGenerator = plugin.methods.resources
    }

Please.. I wish request update to the codes on yours might do the same way.
Or maybe somebody have another solutions for this case.

Thanks.

Using apiKey auth, how do you hide routes that need the key?

I have the following in an app

server.register(require('hapi-auth-bearer-token'), (err) => {
        server.auth.strategy('simple', 'bearer-access-token', {
            allowQueryToken: true,              // optional, true by default
            allowMultipleHeaders: false,        // optional, false by default
            accessTokenName: 'apiKey',    // optional, 'access_token' by default
            validateFunc: ( apiKey, callback ) => {
                // For convenience, the request object can be accessed
                // from `this` within validateFunc.
                var request = this;

                // Use a real strategy here,
                // comparing with a token from your database for example
                if(apiKey === "1234") callback(null, true, { user: 'delaney', roles:['admin']});
                else callback(Boom.badRequest(`you aren't allowed silly`));
            }
        });
    });

And it will get called properly, but if the wrong apiKey is used in the ui, you can still see routes that use the auth. Any ideas?

Document swaggerType Meta Feature

I was about to fork and modify the source code when I spotted the little undocumented feature I actually needed. When implementing OData params, I had $filter, $select, and $where implemented in Joi as Object, Array, and Array respectively (utilizing extension and coerce), but needed them to be sent as strings from swagger. I feel like this functionality probably isn't too uncommon (leading to the decision to add the feature in the first place), so it should really be documented to help future poor saps like me!

Incorrect properties generated for strings with max, min, etc.

When processing a Joi schema which uses max or min to represent the allowable string length, hapi-swaggered generates max & min in the resulting JSON swagger document, rather than maxLength and minLength. This is handled in lib/utils.js, I think in the parseBaseModelAttributes function.

I'm a little short on time, but I will try to show a specific example later.

utils.setNotEmpty doesn't respect value of false

Schema:

const mySchema = Joi.object().keys({
  isNotWorking: Joi.boolean().example(false)
});

Expected Schema:

{
  "isNotWorking": false
}

Actual Schema:

{
  "isNotWorking": true
}

This seems like an easy fix by adding value === false to the end of the conditional block but I wanted to make sure that was an acceptable fix.

utils.setNotEmpty = function (target, key, value) {
  if (!_.isEmpty(value) || _.isNumber(value) || value === false) {
    target[key] = value
  }

  return target
}

Swagger-UI error when not using localhost

Everything works great when viewing with http://localhost/docs.

If I change to host ip, 127.0.0.1, or server.info.host I get an Error {...} button on the /docs/index.html' page after the routes. When I click on it get something like[{"level":"error","message":"Can't read from file http://127.0.0.1:8000/swagger/swagger"}]` however if I set the page directly to that url it resolves fine.

Is there something wrong with my initial config?

Array without schema items creates invalid schema

e.g.

{
  path: '/foobar',
  method: 'post',
  config: {
    tags: ['api'],
    validate: {
      payload: Joi.array().description('foobar').required()
    }
  }
}

swagger validator says:

[
        {
          "code": "OBJECT_MISSING_REQUIRED_PROPERTY",
          "message": "Missing required property: items",
          "path": [
            "definitions",
            "Array_3"
          ]
        },
        {
          "code": "OBJECT_MISSING_REQUIRED_PROPERTY",
          "message": "Missing required property: items",
          "path": [
            "paths",
            "/version/version/array/withouttype",
            "post",
            "parameters",
            "0",
            "schema"
          ]
        },
        {
          "code": "OBJECT_MISSING_REQUIRED_PROPERTY",
          "message": "Missing required property: items",
          "path": [
            "paths",
            "/version/version/array/withouttype",
            "post",
            "responses",
            "default",
            "schema"
          ]
        }
      ]

Automatically generate HEAD methods (option)

As Hapi.js automatically generates HEAD routes for every GET (and based on GET decides what to return), would be cool to allow displaying them, on:

  • global basis (in plugin config object)
  • per route basis (config.plugins['hapi-swaggered'].displayHead = true) - this should check if route.method === GET and if not, ignore (or let user know he's doing something wrong). If displayHead === false - should overwrite global configuration

Source: hapijs/hapi#795

Especially

HEAD is created automatically for every GET you define

and

If you want to optimize your handling of HEAD requests, simply check your GET handler for the method, and if it is 'head', return an empty response with the correct headers. This is only worth doing for some very expensive GET requests, where you are expecting clients to use HEAD directly.

By spec, no payload allowed.

Authentication is the same so HEAD should inherit all GET properties (scope, authentication scheme, error codes) and so on

9.0.x Support?

Hi! I was just wondering if there will be support for 9.X as I'd like to upgrade my system but it crashes because of issues around caching and changes in hapi.

Joi.object().max(10) causing invalid rendering of swagger

Using validation like this

body:{
  foo: Joi.object().max(10)
}

causing hapi-swagger to give an error like this

500 : {"success":false,"error":{"type":"InternalServerError","description":"child \"definitions\" fails because [child \"FooModel\" fails because [child \"properties\" fails because [child \"foo\" fails because [\"maximum\" is not allowed, \"$ref\" is not allowed]]]]","details":"General http error, would be a 500 normally."}} http://localhost:8000/swagger/swagger

with no other rendering on the page except the header.

Joi's documentation says limiting object keys in this fashion is supported. Any thoughts?

file upload does not respect bearer authentication

I am using hapi-swaggered/hapi-swaggered-ui tools.

hapi-swaggered-ui is configured to use a bearer token in api calls via the following config

'hapi-swaggered-ui':{ authorization: { // see above
field: 'Authorization',
scope: 'header', // header works as well
valuePrefix: 'Bearer '// prefix incase
} },

This works great for most calls except file upload calls, which is configured using the method found in the hapi-swaggered documentation for file uploads. In the case of file uploads the configured auth is not sent and no bearer token field is used.

Grouping of endpoints

Hey,
After updating, my endpoints are no longer grouped... They all appear under 'api' tag, instead of being grouped by the first part of the endpoint url, e.g. "auth", "users", "pets".
Any ideas?

Add documentation for response specification

Stuff like this:

{
  config: {
    response: {
      schema: Joi.object({
        bar: Joi.string().description('test').required()
      }).description('test'),
      status: {
        500: Joi.object({
          bar: Joi.string().description('test').required()
        })
      }
    }
  }
}
{
  config: {
    plugins: {
      'hapi-swaggered': {
        responses: {
          default: {description: 'Bad Request'},
          500: {description: 'Internal Server Error'}
        }
      }
    },
    response: {
      schema: Joi.object({
        bar: Joi.string().required()
      }).description('test')
    }
  }
}
{
  config: {
    plugins: {
      'hapi-swaggered': {
        responses: {
          default: {
            description: 'Bad Request', schema: Joi.object({
              bar: Joi.string().description('test').required()
            })
          },
          500: {description: 'Internal Server Error'}
        }
      }
    }
  }
}

FR: Allow to preprocess description (and perhaps others) field before returning it.

Basically, what I would like to do is modifying the description of a route before swagger sends it out, to add some information that can be automatically generated but is not exposed in swagger, like a sentence to remind users that they can paginate through a collection, that kind of stuff.

So for example, the description of the route has "Returns list of customers", and there would be a filter function provided by us; function (routeData...) { return routeData.description + " You can paginate through...." ; }

Explain difference with swaggerize-hapi

Hi,

First of all, thanks for opening your code!

It would be great if you could provide a quick overview of the what led you to write “yet another” implementation as opposed to using swaggerize-hapi, for example, so we can choose more easily which one to use :)

Array of objects turns to array of strings

I define my response schema as follows:

    response: {
        schema: Joi.object().keys({
            code: models.familyCode,
            familyName: models.name.required().description('Family name'),
            accessToken: models.accessToken,
            members: Joi.array(models.familyMember)
        }).meta({ className: 'Login output' }),
        status: {
            400: models.error,
            500: models.error
        }
    }

where models.familyMember is as follows:

familyMember: Joi.object().keys({
        firstName: name.required(),
        lastName: name.required(),
        lastAlive: Joi.date().required(),
        battery: Joi.number().required().min(-1).max(100)
    }).meta({ className: 'Family member' })

Swagger shows the input as follows:

{
  "code": "string",
  "familyName": "string",
  "accessToken": {
    "token": "string",
    "expiration": "2015-11-01T16:18:44.613Z"
  },
  "members": [
    "string"
  ]
}

I can't figure how to solve this issue

stripPrefix not honoured when using host option in request

{
    stripPrefix: '/api/v1',
    basePath: '/alpha',
    host: '1111111.execute-api.us-west-2.amazonaws.com',
}

Each endpoint is prefixed with /api/v1, which has been successfully stripped from the documentation, however, it's adding it to the end of host/basePath which provides an incorrect request destination.

Example Request Destination:
https://1111111.execute-api.us-west-2.amazonaws.com/alpha/api/v1/endpoint

Expected:
https://1111111.execute-api.us-west-2.amazonaws.com/alpha/endpoint

Routes with wildcard method

server.route({
  method: '*'
})

cause this:

Debug: internal, implementation, error
    Error: child "paths" fails because [child "/affiliate" fails because ["*" is not allowed]]
    at Object.exports.create (***/node_modules/hapi/node_modules/boom/lib/index.js:21:17)
    at Object.exports.internal (***/node_modules/hapi/node_modules/boom/lib/index.js:252:99)
    at Object.exports.badImplementation (***/node_modules/hapi/node_modules/boom/lib/index.js:288:23)
    at postValidate (***/node_modules/hapi/lib/validation.js:194:26)
    at internals.Any._validateWithOptions (***/node_modules/joi/lib/any.js:601:16)
    at root.validate (***/node_modules/hapi/node_modules/joi/lib/index.js:102:23)
    at exports.response (***/node_modules/hapi/lib/validation.js:213:20)
    at ***/node_modules/hapi/lib/request.js:331:13
    at iterate (***/node_modules/hapi/node_modules/items/lib/index.js:35:13)
    at done (***/node_modules/hapi/node_modules/items/lib/index.js:27:25)

Array responses not display in swagger-ui

hapi-swaggered: 2.0.0-alpha2
swagger-ui: 2.1.8-M1

{
    "tags": ["api", "jobs"],
    "summary": "List resources",
    "description": "List resources",
    "responses": {
        "default": {
            "type": "array",
            "items": {
                "$ref": "#/definitions/Job"
            }
        }
    },
    "produces": ["application/json"]
}

Whats the correct shema? May swagger-ui issue?
@z0mt3c: Have a look :-)

Btw - no issue about the referenced schema - following works great:

"responses": {
    "default": {
        "schema": {
            "$ref": "#/definitions/Job"
        }
    }
}

Semver is used incorrectly

A microservice of mine was specifying version ^2.2.1 of this repo in its package.json which indicates that it should pull any version below 3.0.0. The service had not been deployed since early January and it broke on npm install during a recent redeployment. This appears to be due to the fact that v2.6.0 is not backwards compatible with Hapi prior to v10.0.0. Breaking changes should increment the major version so I believe the current release should be correctly titled v3.0.0.

Cannot display array with multiple items in Responses or Request Models

First of all thank you for this module! I am really liking it so far but have run into one issue. I have the following schema

var firstObj = Joi.object({
    prop1: Joi.string().only('apple').required(),
    prop2: Joi.string().only('banana').required()
}).required();

var secondObj = Joi.object({
    prop1: Joi.number().required()
}).required();

var userId = Joi.string().only('userId').required();

var batchResponse = Joi.array().items(firstObj, secondObj, userId);

and am including it as my response using the plugin way with schema:

config: {
    plugins: {
        'hapi-swaggered': {
            responses: batchResponse
        }
    }
}

Since this models an array with three Joi objects that are each required, I would expect the Response Model schema in the docs to look something like

[
  {
    "prop1": "apple",
    "prop2": "banana",
    "prop3": "Each response object will vary depending on the requests submitted"
  },
  {
    "prop1": 0
  },
  "userId": "userId"
]

But that's not the case. What shows up in the docs instead is

[
  "string"
]

Am I missing something here? I can get one object to appear in the Response Model array if I remove the required() from the array item models, but still cannot figure out how to display an array containing multiple Joi objects in the Response Schema. Is there a way to do this?

I am using the most current versions of hapi-swaggered (2.6.0), hapi-swaggered-ui (2.3.1), and joi (8.0.5)

Thank you very much!!

Using Joi.ref causes the resulting swagger to be invalid

When doing validation of a field by using Joi.ref() the resulting enum value is null causing swagger-ui to break with the error Uncaught TypeError: Swagger 2.0 does not support null types ()..

Example:

validate: {
    payload: Joi.object({
      currentPassword: Joi.string().required().description("current password"),
      newPassword: Joi.string().required().description("new password"),
      confirmPassword: Joi.string().required().valid(Joi.ref("newPassword")).description("new password again")
    })
  },

Resulting definition:

"CurrentPasswordNewPasswordConfirmPasswordModel": {
      "required": [
        "currentPassword",
        "newPassword",
        "confirmPassword"
      ],
      "properties": {
        "currentPassword": {
          "type": "string",
          "description": "current password"
        },
        "newPassword": {
          "type": "string",
          "description": "new password"
        },
        "confirmPassword": {
          "type": "string",
          "description": "new password again",
          "enum": [
            null
          ]
        }
      }
    }

It would make sense to simply ignore the valid part and remove the enum from the resulting swagger in this case.

Be more lenient with errors

I occasionally get errors like this:

151023/120031.943, [error], message: Uncaught error: swagger-resource generation failed stack: Error: Uncaught error: swagger-resource generation failed
  at Object.exports.assert (/Users/mwawrusch/Documents/envy/backend/envy-api/node_modules/hoek/lib/index.js:731:11)
  at /Users/mwawrusch/Documents/envy/backend/envy-api/node_modules/hapi-swaggered/lib/index.js:65:14
  at /Users/mwawrusch/Documents/envy/backend/envy-api/node_modules/hoek/lib/index.js:849:22
  at doNTCallback0 (node.js:417:9)
  at process._tickDomainCallback (node.js:387:13)

Debug: internal, implementation, error 
    Error: Uncaught error: swagger-resource generation failed
  at Object.exports.assert (/Users/mwawrusch/Documents/envy/backend/envy-api/node_modules/hoek/lib/index.js:731:11)
  at /Users/mwawrusch/Documents/envy/backend/envy-api/node_modules/hapi-swaggered/lib/index.js:65:14
  at /Users/mwawrusch/Documents/envy/backend/envy-api/node_modules/hoek/lib/index.js:849:22
  at doNTCallback0 (node.js:417:9)
  at process._tickDomainCallback (node.js:387:13)

when swaggered has troubles parsing joi (especially with alternatives). This happens with correct code, which forces us to rewrite our validations and make them less exact. A better error handling mechanism would be greatly appreciated. I think most people rather have a mostly correct result then no result at all.

Thanks

Reverse proxy support

Currently, we have a reverse proxy in front of where we are hosting hapi-swaggered that is using path namespacing for the individual apps. Because of this, there is a base path that hapi-swaggered is not aware of, so all of the routes generated produce invalid URLs since this base path is not being added on.

Could we add a basePath or similar configuration parameter to prefix all routes with when generating the resulting URLs?

Working with multiple server connections

I would like to host swagger and the ui on a different connection than the api. Is there a way to accomplish this?

The following is a snippet from a manifest.js file, used with glue.

connections: [
    {
        port: 3000,
        labels: ['api']
    },
    {
        port: 3001,
        labels: ['docs']
    }
],
{
    'hapi-swaggered': [
        {
            select: ['docs'],
            options: {
                info: {
                    title: 'Api Documentation',
                    description: 'REST API Documentation',
                    version: pkg.version
                }
            }
        }
    ]
},
{
    'hapi-swaggered-ui': [
        {
            select: ['docs'],
            options: {
                title: 'Api Documentation',
                path: '/docs',
                authorization: false,
                swaggerOptions: {
                    validatorUrl: null
                }
            }
        }
    ]
}

really long model names

Hi,
I am trying out this plugin but I have problem right from the start. The generated model names are so long, they push model information off screen.

image

Is there some way to influence the name? Seems to me that better name generating scheme for payload might be 'payload'+path+httpMethod. I can have documents with a lot of fields and the names are, as you can see, quite crazy :)

Thank you for the plugin. Seems nice :)

[Question] custom headers

Hi, @z0mt3c

how can i add custom header to the swagger ui via your plugin?

i need to send the request with custom headers and i dont understand where can i add this headers in the browser ui

Be more lenient with versions

Right now hapi-swaggered requires a < 11.0 hapi dependency, which means we cannot run it with 11.0 (but it most likely will work). I get why you put it in there, but I think for convenience' sake it would be good to just specify a lower bound. People version their production systems explicitly anyways, so if a hapi update breaks swaggered it's not a big deal.

BTW, really great module.

response options ignored

When setting

response: {
        modify: true,
        options: {
          stripUnknown: true,
          presence: 'required'
        }
      },

all values are optional anyway.

missing joi.alternatives fields in model

I have a fairly complex validation object shared on multiple routes. Sometimes with slight modifications which are handled by joi.alternatives:

//generic.id = Joi.alternatives().try(
//  Joi.string().length(24).alphanum().lowercase(),
//  Joi.object().type(mongoose.Types.ObjectId)
//);
exports.request = Joi.object().keys({
  name: Joi.string().required().min(3).max(50).regex(/^[a-z0-9][a-z0-9-]+$/),
  state: exports.state.state,
  //only require hgroup on create
  hgroup: generic.id.when('$isCreate', { is: Joi.any().only(true).required(), then: Joi.required() }),
  cdrom: Joi.alternatives().when('cdpath', {is: Joi.any().only(undefined), then:generic.id, otherwise: Joi.any().forbidden()}),
  cdpath: Joi.string().regex(/^[^\/\s](?:(?!\/\.\.\/).)+\.iso$/i), //match any string ending with .iso not containing /../ and not beginning with /
  ram: Joi.number().integer().required(),
  cpuno: Joi.number().integer().required(),
  hdds: Joi.array().required().items(Joi.object().rename('id', '_id').keys({
    _id: Joi.alternatives().when('$isCreate', {
      is: Joi.any().only(true).required(),
      then: Joi.any().forbidden(),
      otherwise: generic.id
    }),
    size: Joi.number().integer().required(),
    description: Joi.string().max(300),
    template: generic.id,
    storage: Joi.string().required()
  })),
  nics: Joi.array().required().items(Joi.object().rename('id', '_id').keys({
    _id: Joi.alternatives().when('$isCreate', {
      is: Joi.any().only(true).required(),
      then: Joi.any().forbidden(),
      otherwise: generic.id
    }),
    ip: Joi.string().required().lowercase().regex(/^(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/),
    subnet: Joi.string().required().lowercase().regex(/^(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/),
    gateway: Joi.string().lowercase().regex(/^(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/),
    vlan: Joi.number().integer().required(),
    description: Joi.string().max(300),
  })),
}).meta({className:'VMRequest'});

Alternatives fields seems to be ignored completely in generated model:

VMRequest {
name (string),
state (string) = ['stopped' or 'running' or 'restarting' or 'destroying'],
cdpath (string, optional),
ram (integer),
cpuno (integer),
hdds (Array[_idSizeDescriptionTemplateStorageModel]),
nics (Array[_idIpSubnetGatewayVlanDescriptionModel])
}
_idSizeDescriptionTemplateStorageModel {
size (integer),
description (string, optional),
storage (string)
}
_idIpSubnetGatewayVlanDescriptionModel {
ip (string),
subnet (string),
gateway (string, optional),
vlan (integer),
description (string, optional)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.