From 858d43c96678abc9ae2c934312dbd164364b8f3d Mon Sep 17 00:00:00 2001 From: Liam Tait Date: Tue, 4 Jul 2023 15:37:13 +1200 Subject: [PATCH 1/3] feat: add route, openapi and swagger objects to transform --- index.d.ts | 10 ++++-- lib/spec/openapi/index.js | 2 +- lib/spec/swagger/index.js | 2 +- test/transform.js | 64 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index cdf4665d..f1cbe3a7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,4 @@ -import { FastifyPluginCallback, FastifySchema, onRequestHookHandler, preHandlerHookHandler } from 'fastify'; +import { FastifyPluginCallback, FastifySchema, FastifyRequest, onRequestHookHandler, preHandlerHookHandler } from 'fastify'; import { OpenAPI, OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'; /** @@ -124,7 +124,13 @@ declare namespace fastifySwagger { /** * custom function to transform the route's schema and url */ - transform?: ({ schema, url }: { schema: S, url: string }) => { schema: FastifySchema, url: string }; + transform?: ({ schema, url, route, swaggerObject, openapiObject }: { + schema: S, + url: string, + route: FastifyRequest, + swaggerObject: Partial + openapiObject: Partial + }) => { schema: FastifySchema, url: string }; refResolver?: { /** Clone the input schema without changing it. Default to `false`. */ diff --git a/lib/spec/openapi/index.js b/lib/spec/openapi/index.js index c290a1b0..a4638016 100644 --- a/lib/spec/openapi/index.js +++ b/lib/spec/openapi/index.js @@ -29,7 +29,7 @@ module.exports = function (opts, cache, routes, Ref, done) { for (const route of routes) { const transformResult = defOpts.transform - ? defOpts.transform({ schema: route.schema, url: route.url }) + ? defOpts.transform({ schema: route.schema, url: route.url, route, openapiObject }) : {} const schema = transformResult.schema || route.schema diff --git a/lib/spec/swagger/index.js b/lib/spec/swagger/index.js index 2b266fe1..b300444a 100644 --- a/lib/spec/swagger/index.js +++ b/lib/spec/swagger/index.js @@ -27,7 +27,7 @@ module.exports = function (opts, cache, routes, Ref, done) { swaggerObject.paths = {} for (const route of routes) { const transformResult = defOpts.transform - ? defOpts.transform({ schema: route.schema, url: route.url }) + ? defOpts.transform({ schema: route.schema, url: route.url, route, swaggerObject }) : {} const schema = transformResult.schema || route.schema diff --git a/test/transform.js b/test/transform.js index bba01a3b..d23959e7 100644 --- a/test/transform.js +++ b/test/transform.js @@ -56,3 +56,67 @@ test('transform should work with a Function', async (t) => { await fastify.ready() t.doesNotThrow(fastify.swagger) }) + +test('transform can access route', async (t) => { + t.plan(5) + const fastify = Fastify() + + await fastify.register(fastifySwagger, { + openapi: { info: { version: '1.0.0' } }, + transform: ({ route }) => { + t.ok(route) + t.equal(route.method, 'GET') + t.equal(route.url, '/example') + t.equal(route.constraints.version, '1.0.0') + return { schema: route.schema, url: route.url } + } + }) + fastify.get('/example', { constraints: { version: '1.0.0' } }, () => {}) + + await fastify.ready() + t.doesNotThrow(fastify.swagger) +}) + +test('transform can access openapi object', async (t) => { + t.plan(4) + const fastify = Fastify() + + await fastify.register(fastifySwagger, { + openapi: { info: { version: '1.0.0' } }, + transform: ({ route, openapiObject }) => { + t.ok(openapiObject) + t.equal(openapiObject.openapi, '3.0.3') + t.equal(openapiObject.info.version, '1.0.0') + return { + schema: route.schema, + url: route.url + } + } + }) + fastify.get('/example', () => {}) + + await fastify.ready() + t.doesNotThrow(fastify.swagger) +}) + +test('transform can access swagger object', async (t) => { + t.plan(4) + const fastify = Fastify() + + await fastify.register(fastifySwagger, { + swagger: { info: { version: '1.0.0' } }, + transform: ({ route, swaggerObject }) => { + t.ok(swaggerObject) + t.equal(swaggerObject.swagger, '2.0') + t.equal(swaggerObject.info.version, '1.0.0') + return { + schema: route.schema, + url: route.url + } + } + }) + fastify.get('/example', () => {}) + + await fastify.ready() + t.doesNotThrow(fastify.swagger) +}) From eb8ed41010fe425f98563e7811bab9a4fa9df767 Mon Sep 17 00:00:00 2001 From: Liam Tait Date: Tue, 4 Jul 2023 16:02:48 +1200 Subject: [PATCH 2/3] docs --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b4612e1e..d0b92918 100644 --- a/README.md +++ b/README.md @@ -226,11 +226,14 @@ An example of using `@fastify/swagger` with `static` mode enabled can be found [ By passing a synchronous `transform` function you can modify the route's url and schema. +You may also access the `openapiObject` and `swaggerObject` + Some possible uses of this are: - add the `hide` flag on schema according to your own logic based on url & schema - altering the route url into something that's more suitable for the api spec - using different schemas such as [Joi](https://github.com/hapijs/joi) and transforming them to standard JSON schemas expected by this plugin +- hiding routes based on version constraints This option is available in `dynamic` mode only. @@ -241,7 +244,7 @@ const convert = require('joi-to-json') await fastify.register(require('@fastify/swagger'), { swagger: { ... }, - transform: ({ schema, url }) => { + transform: ({ schema, url, route, swaggerObject }) => { const { params, body, @@ -266,6 +269,9 @@ await fastify.register(require('@fastify/swagger'), { // can transform the url if (url.startsWith('/latest_version/endpoint')) transformedUrl = url.replace('latest_version', 'v3') + // can add the hide tag for routes that do not match the swaggerObject version + if (route?.constraints?.version !== swaggerObject.swagger) transformedSchema.hide = true + return { schema: transformedSchema, url: transformedUrl } } }) From fbd06ebbf92a59b8ccb39311485041473f308b58 Mon Sep 17 00:00:00 2001 From: Liam Tait Date: Tue, 4 Jul 2023 16:03:14 +1200 Subject: [PATCH 3/3] add test for hiding routes based on route version constraint --- test/transform.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/transform.js b/test/transform.js index d23959e7..a63cbdce 100644 --- a/test/transform.js +++ b/test/transform.js @@ -120,3 +120,22 @@ test('transform can access swagger object', async (t) => { await fastify.ready() t.doesNotThrow(fastify.swagger) }) + +test('transform can hide routes based on openapi version', async (t) => { + t.plan(1) + const fastify = Fastify() + + await fastify.register(fastifySwagger, { + openapi: { info: { version: '2.0.0' } }, + transform: ({ schema, route, openapiObject }) => { + const transformedSchema = Object.assign({}, schema) + if (route?.constraints?.version !== openapiObject.info.version) transformedSchema.hide = true + return { schema: transformedSchema, url: route.url } + } + }) + fastify.get('/example', { constraints: { version: '1.0.0' } }, () => {}) + + await fastify.ready() + const openapiObject = fastify.swagger() + t.notOk(openapiObject.paths['/example']) +})