seriousme / fastify-openapi-glue Goto Github PK
View Code? Open in Web Editor NEWA plugin for the Fastify webserver to autogenerate a Fastify configuration based on a OpenApi(v2/v3) specification.
License: MIT License
A plugin for the Fastify webserver to autogenerate a Fastify configuration based on a OpenApi(v2/v3) specification.
License: MIT License
openapi 3.1 is released -- but the openapi-glue dependency https://github.com/APIDevTools/swagger-parser won't parse that spec . The repo over there appears slightly dormant. Any plans here for handling that dependency? Or should we try to do PRs on swagger-parser?
FYI, the patch bump to v2.6.8 caused a SIGSEGV fault when running my tests in jest. I suspect it's due to the switch to ESM in the openapi-schema-validator. I recognize that it's not your responsibility as the maintainer to test that the code works in Jest but the switch to ESM in a sub-dependency was an observable change. Feel free to close this issue. π
From version v2.4.1
onwards, property names are missing in the response body. This is due to a breaking change in ajv@8
:
property name is removed from "propertyName" keyword error message (it is still available in error.params.propertyName).
more details here
This issue was introduced in #190 where ajv@7 was upgraded to avj@8. Specific example of missing property name can be seen in updated test in that PR.
I am happy to raise a PR to fix this issue, but need some guidance on what would be the best approach to tackle it.
So far, I found an approach that works.
If the following is added to setValidatorCompiler in index.js:
instance.setSchemaErrorFormatter(function (errors, dataVar) {
return new Error(ajv.errorsText(errors))
})
then the error text will include property name.
However, I am not sure if this is the right place to do so. Potentially, this might need to be addressed in fastify itself since it has its own ajv instance and therefore it might have the same issue. Fastify@3 is using ajv@6, so their schemas work fine.
Hey,
I've recently noticed that the Request body schema validation isnt working as expected (at least for me).
Additional properties are going through as opposed to being ignored and the noAdditional prop doesnt have any effect in my code.
Type validation isnt working either - i can pass whatever value i want to my properties and it will completely ignore them.
I'm on the latest version
i will be adding an example/replication as soon as i'm able to tomorrow but just wanted to post this just in case it's a known issue.
Hello! I have defined my routes in an openapi v2 json that looks something like this
{ "swagger": "2.0", "info": { "title": "Posts API", "description": "Post swagger definition for fastify", "termsOfService": "http://swagger.io/terms/", "contact": { "name": "API Support", "url": "http://www.swagger.io/support", "email": "[email protected]" }, "license": { "name": "Apache 2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0.html" }, "version": "2" }, "tags":[ { "name": "posts", "description":"Posts" } ], "schemes": ["http"], "paths": { "/": { "get": { "summary": "Returns array with all posts", "description": "", "operationId": "getAllPosts", "consumes": ["application/json"], "produces": ["application/json"], "responses": { "200": { "description": "successful operation", "schema": { "type": "array", "items": { "$ref": "#/definitions/Post" } } } } } }, "/add": { "post": { "summary": "Creates a new post", "description": "", "operationId": "createPost", "consumes": ["application/json"], "produces": ["application/json"], "responses": { "201": { "description": "created", "schema": { "$ref": "#/definitions/Post" } } } } } }, "definitions": { "Post": { "type": "object", "required": ["id", "user", "title"], "properties": { "id": { "type": "string" }, "user": { "type": "string" }, "title": { "type": "string", "example": "titulo de ejemplo" } }, "xml": { "name": "Post" } } } }
The problem is that my instance of swagger is not showing in the docs the paths that I created. (They work fine in code, they are being called sucessfully from postman / insomnia) but there is no way to see them on the swagger instance.
Its worth noting that when I create and register a route manually it is shown correctly on the swagger docs.
This is my config:
void fastify.register(openapiGlue, { specification: openapiJson.default, service: new Service(), prefix: "v1", noAdditional: true, ajvOptions: { formats: { "custom-format": /\d{2}-\d{4}/ } } })
void fastify.register(swagger, { routePrefix: "/docs", swagger: { info: { title: "Test swagger", description: "Testing the Fastify swagger API", version: "0.1.0", }, externalDocs: { url: "https://swagger.io", description: "Find more info here", }, host: "localhost", schemes: ["http"], consumes: ["application/json"], produces: ["application/json"], }, uiConfig: { docExpansion: "full", deepLinking: false, }, staticCSP: true, transformStaticCSP: (header) => header, exposeRoute: true, });
Hello!
It seems that there is a problem with a dependency of ajv, when using openapi-glue v2.6.1 it throws an error whenever I want to run the project. Here is the stack:
`Error: Cannot find module 'ajv/dist/core'
Require stack:
It works fine on the 2.5 version of the openapi-glue plugin.
index.js in generated project
service:
${__dirname}service.js,
should be
service:
${__dirname}/service.js,
index.js
// Fastify plugin autogenerated by fastify-openapi-glue
const openapiGlue = require("fastify-openapi-glue");
const options = {
specification: `${__dirname}/openApi.json`,
service: `${__dirname}service.js`,
securityHandlers: `${__dirname}security.js`
};
module.exports = async function(fastify, opts) {
fastify.register(openapiGlue, options);
};
if I call a sub method in my service.js file from the method that was requested by fastify it could not be found.
Sample:
async addPet(req, reply) {
console.log("addPet", req.params);
this.createPet(req.query.name);
return { key: "value" };
}
createPet(name) {
console.log(`Pet ${name} created`);
}
Getting a HTTP 500 error that says this.createPet method not found. Looks like 'this' is losing it's scope.
Hi, I noticed that when posting a number, its converted to string. I did expect a validation error.
I use the below OpenAPI spec:
{
"components": {
"schemas": {
"item": {
"properties": {
"msg": {
"type": "string"
}
},
"type": "object"
}
}
},
"info": {
"title": "API Title",
"version": "1.0"
},
"openapi": "3.0.2",
"paths": {
"/test": {
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/item"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/item"
}
}
},
"description": "OK"
}
}
}
}
}
}
The I generate the project and run it:
npx github:seriousme/fastify-openapi-glue test.json
cd generatedProject/
npm i
npm run dev
Now I hit the server with an http request:
// use vscode extension: humao.rest-client
POST /test HTTP/1.1
Host: localhost:3000
Content-Type: application/json; charset=utf-8
{
"msg": 1
}
and I get this response back:
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 11
Date: Tue, 21 Jun 2022 14:36:35 GMT
Connection: close
{
"msg": "1"
}
The post handler returns the body as is:
async postTest(req, reply) {
return req.body;
}
To get the default export from a dynamic import you need to use
const {default: openapiGlue} = await import('fastify-openapi-glue');
instead of
const openapiGlue = await import("fastify-openapi-glue");
I am using openapi specification to generate a new server. I have the following settings:
...
/dnszone:
get:
tags:
- dnszone
summary: Searches for a certain DNS zone by nameserver name or IP address
description: Provide Type of DNS record and Name in parameters
operationId: dnszoneGET
parameters:
- $ref: '#/components/parameters/StatusDNSZoneParams'
responses:
"200":
...
The value of the StatusDNSZoneParams is:
parameters:
StatusDNSZoneParams:
name: StatusDNSZoneParams
in: query
description: A list of params for an existing DNS zone.
required: true
style: form
explode: false
schema:
$ref: '#/components/schemas/StatusDNSZoneRequestObj'
When I try to call:
curl -X 'GET'
'http://localhost:3000/dnszone?StatusDNSZoneParams=DNSZONE,string,EXTENDED,string'
-H 'accept: application/json'
I receive the error:
{"statusCode":400,"error":"Bad Request","message":"querystring must be object"}
Why would this be a problem?
I tried to change the object serialization by changing explode to true, then tried:
curl -X 'GET' 'http://localhost:3000/dnszone?DNSZONE=string&EXTENDED=string' -H 'accept: application/json'
I get the error:
{"statusCode":400,"error":"Bad Request","message":"querystring must have required property 'StatusDNSZoneParams'"}
Would you please explain the issue here? thanks in advance!
I'm finding that the 'byte' format validation in the new 'oai-formats' will fail after the first validation.
It appears that the Regex object created for each invocation is retaining the 'lastIndex' from the previous validation.
This issue can be replicated by duplicating line 22 of test/test-oai-formats.js
Dear users,
Node.js will end LTS support on Node 10 per May 2021
This means that Node 12.x will be the oldest supported version by then. ECMA Script Modules are supported as of Node.js 12.17.
Therefore my intent is to migrate fastify-openapi-glue
cto ESM per May 2021 by releasing a new major version (3.0.0). I have already migrated the code base in the migrate-to-esm branch.
I might release another 2.4.x version of fastify-openapi-glue
before May 2021 e.g. if security issues popup in the module of one of its dependencies. However: if you plan to submit a PR on fastify-openapi-glue
please create an issue first to discuss !
In the mean time: please make sure you stay reasonably current on the Node.js version you use !
Kind regards,
Hans
12.6.1
to 12.6.2
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
tap is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 3 commits.
fa3f6e2
12.6.2
b8be134
new computer, phantom png changes
3833522
update js-yaml and nyc for vuln advisories
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
Response objects with $ref to a model with null fields. Im getting the current error:
TypeError: Cannot read properties of null (reading 'id')
at $arr$mainvisitsitemsi0meeting (eval at build
This is what I'm getting back from the database and trying to return to the client:
id: 'd64cc7a8-c723-4c4d-9d9c-58dae718074c',
...
meetingId: null,
meeting: null,
Because meeting is null, i didn't expected it to be validated since it's not required in the schema.
Hi, I think it would be good if we could split the code into multiple services. Currently this module only supports a single service.
I want to be able to do something like this:
fastify.register(openApiGlue, {
prefix: 'v1',
specification: openapiSpec,
services: [
new FooService(),
new BarService()
],
});
So I think it would be good to make this by default or allow an option to enable it. Perhaps something like this:
async function generateRoutes(routesInstance, routesOpts) {
const service = opts.services.find(svc => item.operationId in svc)
...
Or maybe it could be a more flexible system, where people can provide their own resolver function and do whatever they wish to add the handler to the item.
async function generateRoutes(routesInstance, routesOpts) {
const resolver = resolverFactory(routesInstance, opts)
config.routes.forEach((item) => {
const handler = resolver(item, routesOpts)
item.handler = handler || notImplemented(item.operationId)
Then we could supply, our own resolvers, if required. For example:
function listResolverFactory(routesInstance, pluginOpts) {
const services = pluginOpts.services;
return function (item, routesOpts) {
const service = services.find(svc => item.operationId in svc)
return service && service[item.operationId].bind(service);
}
}
Or if no resolver was provided, the default resolver could be used:
function defaultResolverFactory(routesInstance, pluginOpts) {
// check is the service property exists and is valid
const service = pluginOpts.service;
checkObject(service, 'service');
// return the resolver function
return function (item, routesOpts) {
const response = item.schema.response;
if (item.operationId in service) {
routesInstance.log.debug(`service has '${item.operationId}'`);
return service[item.operationId].bind(service);
}
}
}
const resolverFactory = opts.resolverFactory || defaultResolverFactory
So we could use the package like this:
fastify.register(openApiGlue, {
prefix: 'v1',
specification: openapiSpec,
resolverFactory: listResolverFactory,
services: [
new FooService(),
new BarService()
],
});
Hello, I have a need to allow additional properties that are not in the model definition to be returned, and the current setting is hardcoded and conflicts with the OpenApi specification which allows additional properties: https://github.com/OAI/OpenAPI-Specification/blame/3.0.2/versions/3.0.2.md#L2305
The following defaults could be made customizable:
const ajv = new Ajv({
// the fastify defaults
removeAdditional: true, <--- perhaps this needs to be false to match the openapi spec
useDefaults: true,
coerceTypes: true
});
ref: https://github.com/seriousme/fastify-openapi-glue/blob/master/index.js#L53
I have two use cases which involve fetching related models that are not defined in the source model:
userId
, however, the getProjects api has an option to specify related models to fetch eagerly, like GET /projects?include=user
.projectId
. I tried defining the project property in the Task model but in practice it causes an infinite loop because a project is already defining tasks as a child props. So it would end up walking this path:Ideally it would be good to decide who much of the features we want to enable in fastify-openapi-glue
, request validation? response validation? type coersion? allow additional properties...etc.
Hello, i am trying to use openapi-glue in a project but i have faced a problem that i would like to know if it should work like this. I have a DELETE endpoint where i can send the ids of the agents i want to delete as query parameters. For example:
/groups/16705c05-3f5c-4e02-95a2-6f3f551c620b/agents?where[id][inq]=278...
.
Here i have the specification for the following endpoint:
delete:
summary: Remove multiple agents from group
description: Remove multiple agents from selection group.
operationId: removeMultipleAgentsFromGroup
tags:
- Agents
parameters:
- name: id
description: Group ID
in: path
required: true
schema:
type: string
format: uuid
- name: where
in: query
description: Items to filter
# style: deepObject
explode: false
schema:
type: object
additionalProperties: false
properties:
id:
type: object
additionalProperties: false
properties:
inq:
type: array
items:
type: string
responses:
200:
description: Agents part of a group.
content:
application/json:
schema:
type: object
properties:
agents:
type: array
items:
type: object
properties:
id:
type: string
priority:
type: integer
count:
type: integer
401:
$ref: 'errors.yaml#/components/responses/Unauthorized'
404:
$ref: 'errors.yaml#/components/responses/NotFound'
500:
$ref: 'errors.yaml#/components/responses/InternalServer'
The problems that i am having are two, on the one hand, i had to add explode false to avoid the parser to parse only the schema of the query parameter (function parseQueryString in openapi-glue). if i don't add it, i don't recieve any information past the openapi validation . The thing is that i want to add style: deepObject which it says that by default sets explode to true, so it is contradictory. (documentation of openapi about style: https://spec.openapis.org/oas/v3.1.0#style-examples )Is this supposed to work like this?
On the other hand, i would like openapi to stop all the queries that have extra query parameters apart from where. For example, if i send the following request /groups/16705c05-3f5c-4e02-95a2-6f3f551c620b/agents?blabla[id][inq]=278
, openapi does not stop this as a bad request. Is there any way to add a additionalProperties: false to the query?
The configuration that i have set for ajv is coerceTypes: 'array'
and i have also tried with removeAdditional: false,
but did not get expected result.
Thank you for your time
Hello there π
First, thank you for the work on this module!
I'm planning on contributing on this project for 2-3 things if possible, but from what I see, there aren't yet any linting or code conventions, which increases the friction for starting contributing.
Usually, I have eslint
, prettier
and editorconfig
helping to keep the code base consistent. I was wondering if you agree, and would like, to have these tools added in your project ?
A good enough article on the setup of this. Note that I can do it myself and submit a PR if you want.
Have a nice day!
given this openapi
openapi: "3.0.0"
info:
title: API
version: 1.0.0
paths:
/:
get:
operationId: getVersion
summary: Show API Version
parameters:
- name: authorization
in: header
schema:
type: string
required: true
security:
- FirebaseToken: []
components:
securitySchemes:
FirebaseToken:
type: http
scheme: bearer
bearerFormat: bearer
I expect that user cannot access endpoint without providing authorization
header
Is it possible to configure select routes with preHandler
methods? This will enable us to secure specific routes that require authenticated users or operations that require specific roles or permissions.
This also leads to the following question. Does fastify-openapi-glue
play nice with other plugins that hook into the routes lifecycle?
Example:
fastify.route({
method: 'POST',
url: '/auth-multiple',
preHandler: fastify.auth([
fastify.asyncVerifyJWTandLevel,
fastify.asyncVerifyUserAndPassword
]),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
Hello !
I noticed that when an operation overrides the global security with an empty array, thus specifying that no security should be applied on this operation, it still somehow tries to validate the access to the route (and throws an error).
More specifically, and according to https://swagger.io/docs/specification/authentication/, if an operation has (e.g.)
...
security:
- ApiKeyAuth: []
- OAuth2:
- read
- write
paths:
/ping:
get:
security: [] # No security
The route should be accessible publicly.
Currently, from what I see, it throws the default error. From what I checked, I think the check here should additionally check if the schemes array is empty or not. Doing so will bypass the security when the array is empty.
if (!schemes || schemes.length === 0) {
What do you think ? I'm open to do a MR for this
This could be seen as a breaking change, as if some people using the lib have "badly" configured security rules in their Open API specs and were happy with this default handler, it will suddenly change "badly configured" protected routes to unprotected routes
The value of options.service
can be passed in as a function which will be executed during import:
fastify.register(require("fastify-openapi-glue"), {
specification: `${__dirname}/petstore-swagger.v2.json`,
service: () => return new Service()
});
Currently only synchronous functions are allowed. Adding support for async functions would give service implementors more flexibility:
fastify.register(require("fastify-openapi-glue"), {
specification: `${__dirname}/petstore-swagger.v2.json`,
service: async () => {
const dataProvider = await DataStore.create();
return new Service(dataProvider);
}
});
There are no typescript typings for fastify-openapi-glue
Hello, thanks for this nice plugin! Would it be possible to support passing of an array or map of services? This would allow us to organize functionality into multiple classes that represent different domains. An example would be UserService for user crud operations and, RoleService for the role specific operations...etc. Another example is a shopping cart application with catalog, cart and checkout services. It would be cumbersome to add all in one file.
Hi,
I struggled a bit to get fastify running with openapi glue.
If I start the fastify server I get following error:
FST_ERR_SCH_BUILD: Failed building the schema for POST: /MyPath, due error undefined unsupported
I created a minimum repro with the attached swagger file:
Maybe something is wrong with my swagger file but the online swagger editor mentioned no errors.
Can someone give me a hint what is going wrong here?
I noticed that the generated routes ignore the servers/url parameter (this is the equivalent of basePath in openApi v2) defined in the specs yaml file for openApi v3.
E.g.
openapi: '3.0.0'
servers:
- url: /api/v3
paths:
/info:
get:
....
Expected:
Route generated with path /api/v3/info
Actual:
Route generated with path /info
Just wanted to check if this is intended, or just not yet supported.
current workaround is to install the dependency via the github handle
npm install seriousme/fastify-openapi-glue
using this on fastify 3 will invoke an error on instance.setSchemaCompiler
on index.js
besides the above. love the library! thank you for your work!
According to OpenAPI 3 the following definition should be valid:
...
paths:
/users/{id}:
parameters:
# definition of parameters for all methods of this path, e.g.
- name: id
in: path
required: true
get:
# definition of a get request
...
post:
# definition of a post request
...
But when the parameters
key of a Path Object is used, it seems to be handled like the get
, post
, etc. keys, so it is used as a definition of an additional method here.
Error: PARAMETERS method is not supported!\n
at Object.route (/path/to/project/node_modules/fastify/lib/route.js:118:15)\n
at Object._route [as route] (/path/to/project/node_modules/fastify/fastify.js:162:27)\n
at config.routes.forEach.item (/path/to/project/node_modules/fastify-openapi-glue/index.js:80:22)\n
at Array.forEach (<anonymous>)\n
at generateRoutes (/path/to/project/node_modules/fastify-openapi-glue/index.js:67:19)\n
at Plugin.exec (/path/to/project/node_modules/avvio/plugin.js:89:17)\n
at Boot.loadPlugin (/path/to/project/node_modules/avvio/plugin.js:175:10)\n
at release (/path/to/project/node_modules/fastq/queue.js:127:16)\n
at Object.resume (/path/to/project/node_modules/fastq/queue.js:61:7)\n
at Plugin.finish (/path/to/project/node_modules/avvio/plugin.js:166:10)
Instead, this parameters
object should be merged into all method definitions.
Hi,
I converted the petstore-swagger.v2.json to openAPI 3 with editor.swagger.io. I noticed that v3 no longer requires basePath and it will be substitute by servers array.
"servers": [
{
"url": "http://petstore.swagger.io/v3"
}
],
However, when swapped with the petstore example:
const options = {
specification: ${__dirname}/petstore-swagger.v3.json
,
service: ${__dirname}/service.js
};
curl -s -XGET http://localhost:3000/v3/pet/24 -H "accept: application/json" | python -m json.tool
{
"error": "Not Found",
"message": "Route GET:/v3/pet/24 not found",
"statusCode": 404
}
If "v3" is removed from the server URL then it works like this, BUT notice that the photoUrl key was not returned:
curl -s -XGET http://localhost:3000/pet/24 -H "accept: application/json" | python -m json.tool
{
"id": 24,
"name": "Kitty the cat",
"photoUrls": [],
"status": "available"
}
Any idea how to retain the server url as specified in the specification and how to return correct photoUrls?
Thanks.
The following schema break application without giving any errors or warnings
components:
schemas:
baseUser:
type: "object"
properties:
username:
type: "string"
email:
type: "string"
format: "email"
is_verified:
type: "boolean"
newUser:
allOf:
- type: "object"
properties:
password:
type: "string"
- $ref: "#/components/schemas/baseUser"
Application starts working fine if allOf
is removed or if there is only a sinlge sub-schema under allOf
.
I am using fastify-openapi-glue
as a middleware to Fastify server.
Hello, im having an issue importing this module when running even the simplest example. After upgrading this package from 2.7.x to latest, I'm getting this error when attempting to import
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in /Users/x/node_modules/fastify-openapi-glue/package.json
at new NodeError (node:internal/errors:372:5)
at throwExportsNotFound (node:internal/modules/esm/resolve:472:9)
at packageExportsResolve (node:internal/modules/esm/resolve:693:7)
at resolveExports (node:internal/modules/cjs/loader:482:36)
at Function.Module._findPath (node:internal/modules/cjs/loader:522:31)
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:919:27)
at Function.Module._load (node:internal/modules/cjs/loader:778:27)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/Users/x/dist/index.js:18:43) {
code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Is it something with the new esm
update? I'm using typescript 4.7.4 and im using node 16.
index.ts
import fastify from "fastify";
import cors from "@fastify/cors";
import fastifyOpenapiGlue from "fastify-openapi-glue";
// const fastifyOpenapiGlue = require("fastify-openapi-glue");
const app = fastify();
app.register(cors);
app.register(fastifyOpenapiGlue);
console.log("fastify", fastify);
tsconfig.json
{
"compilerOptions": {
"target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"module": "CommonJS" /* Specify what module code is generated. */,
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
"strict": true /* Enable all strict type-checking options. */,
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
start script:
tsc && node index.js
Hi there, I'm working on understanding the best use of fastify-openapi-glue with respect to accessing the schemas defined within the OpenAPI document.
Mainly my digging has lead me to believe that as the schemas are defined in the YML file, and that file is loaded at app start, I would think that the schemas should all be available through fastify.getSchemas() which would then allow me to use them in part to further validate the incoming data with custom validation (ex: validation of multiple fields, searching the database for unique values, and so on).
However, when I examine fastify.getSchemas() this appears to be empty. Is there another way to access the schemas as they are loaded from glue so that I can use Ajv ahead of time to set up the validations where I would simply pass the request to?
In addition to the above, I would love to have the data available in a prepared POJO (like a global fastify schema) that that has been filtered which I could then pass around into other functions or methods instead of using request.body which may contain data that hasn't been treated. The alternative here is that I have to write a POJO and fill it myself from the request.body to then be able to use as I see fit.
Is there a best way from your experience to load schemas into the global collection via fastify.addSchemas?
Thoughts and thanks for your time in advance on this question.
It would be useful to generate TypeScript somewhat like this (based on what I see in this example):
type AddPetParams = {
id?: number,
category?: {id?: number, name?: string},
/** @example "doggie" */
name: string,
photoUrls: []string,
tags?: []{id?: number, name?: string},
status?: 'available' | 'pending' | 'sold',
}
type Pet = {
//...
}
async addPet(req: Req<AddPetParams>): Pet {
console.log("addPet", req.params);
return { name: "doggie", photoUrls: [] };
}
I'm using fastify-openapi-glue on several projects and i faced an issue regarding additionnalProperties:false
. Because of this line : https://github.com/seriousme/fastify-openapi-glue/blob/master/index.js#L53
Is it possible to add a parameter for this? This would lead in a HTTP 400
is there is additionnal properties.
I can write a PR for this.
Hi
I've a problem with 2.6.8 version of this plugin. With 2.6.7 my yaml swagger specification file works fine, but with 2.6.8 update i've this error:
ENOENT: no such file or directory, open '/D:/pode/ts-employee-backend-write/node_modules/@seriousme/openapi-schema-validator/schemas/v2.0/schema.json'
Error: 'specification' parameter must contain a valid version 2.0 or 3.0.x or 3.1.x specification
at parser.parse (D:\pode\ts-employee-backend-write\node_modules\fastify-openapi-glue\lib\parser.js:54:13)
at async fastifyOpenapiGlue (D:\pode\ts-employee-backend-write\node_modules\fastify-openapi-glue\index.js:114:18)
My code with openapi-glue is very simple:
import FastifyOpenApiGlue from 'fastify-openapi-glue';
.
.
.
.
const openapiGlueOptions = {
specification: path.join(__dirname, 'api/swagger.yaml'),
service: new WriteController()
};
const app = Fastify({
bodyLimit: 524288,
maxParamLength: 200
});
app.register(FastifyOpenApiGlue, openapiGlueOptions);
This is an example that works with 2.6.7 but brokes with 2.6.8
swagger: "2.0"
info:
description: |
TODO
version: "5.0.1"
title: WIP
termsOfService: http://swagger.io/terms/
contact:
email: [email protected]
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
externalDocs:
description: Find out more about Swagger
url: http://swagger.io
basePath: /
schemes:
- https
- http
produces:
- application/json
paths:
/docs/isReady:
get:
tags:
- Probes
summary: isReady (for k8s readiness probe)
description: isReady (for k8s readiness probe)
operationId: isReady
responses:
200:
description: isReady
500:
description: ko
Sorry for my poor English
Filippo
Hi,
it seems that fastify-openapi-glue doesn't support multipart/form-data requests at all. I notice some warnings at service startup
body type: multipart/form-data found
and there's no input validation.
If I call my service with multipart/form-data body it returns 415 with FST_ERR_CTP_INVALID_MEDIA_TYPE
error message.
Currently, when registering the openapi-glue
with fastify
, you can specify ajvOption
s such as:
await fastifyApp.register(openapiGlue, {
specification: <myapi spec>,
service: <myService>,
prefix: <myAPIPrefix>,
ajvOptions: {
coerceTypes: false
}
});
The drawback of this is that if you set coerceTypes
to true, it enables type coercion on all parts of the message. This issue is to allow enabling type coercion on each part of the HTTP message separately. An example ajvOptions
object might look like:
ajvOptions: {
coerceParms: true | false,
coerceBody: true | false,
coerceQueryString: true | false,
coerceHeaders: true | false
}
I used fastify-openapi-glue
with a vanilla JS project and it worked great:
https://github.com/Postman-Student-Program/restaurant-api-example/tree/chapter-3-persisting-data
Now I'm using TypeScript with the same setup but validation errors (400
) are not being caught be fastify. Cryptic 500
errors are being returned from the API
server.ts
import Fastify from 'fastify'
import openapiGlue from 'fastify-openapi-glue'
import RouteHandler from './RouteHandler'
const glueOptions = {
specification: `${__dirname}/schema.yaml`,
service: new RouteHandler()
}
const fastify = Fastify({ logger: true })
fastify.register(openapiGlue, glueOptions)
const PORT = process.env.PORT || 4000
fastify.listen(PORT, (err, address) => {
if (err) {
console.error(err)
process.exit(1)
}
console.log(`Server listening at ${address}`)
})
RouteHandler.ts
import { FastifyReply, FastifyRequest } from 'fastify'
import context from './context'
import { castGetBooksParams, filterObj } from './utils'
import requireApiKey from './validations/requireApiKey'
const { booksService } = context.services
class RouteHandler {
constructor() {}
healthcheck = (_req: FastifyRequest, res: FastifyReply) => {
return res.send({ message: 'ok' })
}
getBooks = async (req: FastifyRequest, res: FastifyReply) => {
const params = castGetBooksParams(req.query as GetBooksParamsRaw)
const books = await booksService.getBooks(params)
return res.send(books)
}
createBook = async (req: FastifyRequest, res: FastifyReply) => {
requireApiKey(req)
const newBook = await booksService.createBook(req.body as CreateBookInput)
return res.status(201).send(newBook)
}
getBook = async (req: FastifyRequest, res: FastifyReply) => {
const book = await booksService.getBook(req.params as IdParams)
return res.send(book)
}
updateBook = async (req: FastifyRequest, res: FastifyReply) => {
requireApiKey(req)
const params = req.params as IdParams
const input = req.body as UpdateBookInput
const book = await booksService.updateBook(params, input)
return res.send(book)
}
deleteBook = async (req: FastifyRequest, res: FastifyReply) => {
requireApiKey(req)
const params = req.params as IdParams
await booksService.deleteBook(params)
return res.code(204).send()
}
}
export default RouteHandler
example part of schema.yaml
for POST /books
/books:
post:
summary: 'Add a book'
operationId: createBook
security:
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateBookInput'
responses:
'201':
description: 'Book created successfully'
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
'400':
description: 'Bad Request'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'Unauthorized'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
default:
description: 'Unexpected error'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
....
components:
schemas:
CreateBookInput:
type: object
required:
- title
- author
- genre
- yearPublished
properties:
title:
type: string
minLength: 1
author:
type: string
minLength: 1
genre:
type: string
minLength: 1
yearPublished:
type: integer
Trying to send a POST request to /books with a missing parameter returns a 500 error (expect 400 error with "missing" property type)
response from Fastify API
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "\"status\" is required!"
}
12.6.0
to 12.6.1
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
tap is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 4 commits.
1871736
12.6.1
066f159
updates for npm audit --fix
ad3bed4
Passes -r ts-node/register
argument to node
4645ecf
Fix font-family typo
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
In function makeSchema
I found that tags, summary, description, operationId
properties are adding in schema, so I think whould be very useful to add custom properties (which starts with x-
) in schema too.
Hi!
If I throw an error within the securityhandler, like this:
throw new ForbiddenError('User don't have permission to requested resource');
throw new InternalServerError('Technical error, please try again later');
Its caught here https://github.com/seriousme/fastify-openapi-glue/blob/master/lib/securityHandlers.js#L69 and the statuscode gets overridden to always return 401.
I rather have it return the error catched here https://github.com/seriousme/fastify-openapi-glue/blob/master/lib/securityHandlers.js#L57 than wrapping it in a general error with wrong code.
Thanks!
NPM can find this package, but Yarn can't. Looks like it should be in https://registry.yarnpkg.com/fastify-openapi-glue, but it isn't.
Hi. Is there any reason that testing cannot be implemented as a part od the setup script? If the only constraint is developer time I'd like to give it a go.
0.26.1
to 0.26.2
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
fastify-cli is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
#138 - Normalize line endings
The new version differs by 5 commits.
34b3fbf
0.26.2
f02a712
Add node 11 to ci (#141)
cd1716a
Normalize line endings in tests (#140)
be2a549
Add attributes file
36229e3
Add test for glob pattern (#135)
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
Passing an AJV instance into this plugin would result in fewer direct dependencies for this package and more customizability from a user's perspective. Not everyone needs the extra ajv format options so they could optimize their code by not including it or by only including the extra formats that they need.
Only last schema is being used for endpoints with multiple mimetypes:
fastify-openapi-glue/lib/parser.v3.js
Lines 71 to 80 in a0269cf
which contradicts the spec stating that Schemas can vary by media type.
Therefore, following sample spec will not consume text/plain
requests by throwing
{
"statusCode": 400,
"error": "Bad Request",
"message": "body should be object"
}
openapi: 3.0.0
info:
version: 1.0.0
title: Test
paths:
"/test":
post:
summary: Multiple mimetypes payload
operationId: test
requestBody:
content:
text/plain:
schema:
type: string
application/json:
schema:
$ref: "#/components/schemas/TestMessage"
responses:
"200":
description: Message received
components:
schemas:
TestMessage:
type: object
nullable: true
properties:
id:
type: number
description: Id
Calling this
in a route handler refers to the service
object instead of fastify
. This causes lost references to fastify
and possibly other plugins attached to the fastify
object. It may have been broken in #73
For example, when used with fastify-mongo:
fastify.get('/user/:id', function (req, reply) {
const db = this.mongo.db // throws because fastify.mongo no longer exists
...
})
From Fastify docs:
handler(request, reply)
: the function that will handle this request. The Fastify server will be bound tothis
when the handler is called. Note: using an arrow function will break the binding of this.
I'm working around this by adding fastify
back to the service object, but it may cause confusion for other users (as it did for me) when installing this plugin and following along with the docs.
const options = {
specification: 'swagger.yaml',
prefix: 'v1',
noAdditional: true,
service: () => ({
fastify: app,
handleRequest
}),
};
Possible solutions:
service
and fastify
:If this is where it's happening, something like:
async function generateRoutes(routesInstance, opts) {
config.routes.forEach(item => {
const response = item.schema.response;
if (response) {
stripResponseFormats(response);
}
if (service[item.operationId]) {
routesInstance.log.debug("service has", item.operationId);
item.handler = service[item.operationId].bind({...service, ...routeInstance}); // maybe? not sure if routeInstance is the fastify instance
} else {
item.handler = async (request, reply) => {
throw new Error(`Operation ${item.operationId} not implemented`);
};
}
routesInstance.route(item);
});
}
If I'm not missing something, and this is indeed an issue, I'll gladly create a PR.
Fastify now supports keyword "nullable" from Open API 3 specification and it's set in its baseline ajv configuration: https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md. Can we have something like that in index.js:
const ajv = new Ajv({
// the fastify defaults
removeAdditional: true,
useDefaults: true,
coerceTypes: true,
nullable: true, // add this line
});
Thanks in advance.
Hey,
Could it be possible to add another option or extend the ajvOptions to use user given ajv instance instead of creating your own. The problem is here: https://github.com/seriousme/fastify-openapi-glue/blob/master/index.js#L60 the usage setValidatorCompiler overrides anything user might want and setValidatorCompiler was pretty much added so that user can override ajv instance on the fastify, but using this tool that's impossible.
I did a small patch https://github.com/seriousme/fastify-openapi-glue/blob/master/index.js#L56 on that line with following:
- const ajv = new Ajv(ajvOptions);
+ const ajv = ajvOpts || new Ajv(ajvOptions);
To let me able to pass the ajv instance through the ajvOptions.
Would it be possible to add this as ajvInstance option (override ajv instance which doesn't take ajvOptions into account or such).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.