Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add custom decorator support #837

Merged
merged 6 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 70 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,18 +230,19 @@ An example of using `@fastify/swagger` with `static` mode enabled can be found [

#### Options

| Option | Default | Description |
| ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| hiddenTag | X-HIDDEN | Tag to control hiding of routes. |
| hideUntagged | false | If `true` remove routes without tags from resulting Swagger/OpenAPI schema file. |
| initOAuth | {} | Configuration options for [Swagger UI initOAuth](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). |
| openapi | {} | [OpenAPI configuration](https://swagger.io/specification/#oasObject). |
| stripBasePath | true | Strips base path from routes in docs. |
| swagger | {} | [Swagger configuration](https://swagger.io/specification/v2/#swaggerObject). |
| transform | null | Transform method for the route's schema and url. [documentation](#register.options.transform). | |
| transformObject | null | Transform method for the swagger or openapi object before it is rendered. [documentation](#register.options.transformObject). | |
| refResolver | {} | Option to manage the `$ref`s of your application's schemas. Read the [`$ref` documentation](#register.options.refResolver) |
| exposeHeadRoutes | false | Include HEAD routes in the definitions |
| Option | Default | Description |
| ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| hiddenTag | X-HIDDEN | Tag to control hiding of routes. |
| hideUntagged | false | If `true` remove routes without tags from resulting Swagger/OpenAPI schema file. |
| initOAuth | {} | Configuration options for [Swagger UI initOAuth](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). |
| openapi | {} | [OpenAPI configuration](https://swagger.io/specification/#oasObject). |
| stripBasePath | true | Strips base path from routes in docs. |
| swagger | {} | [Swagger configuration](https://swagger.io/specification/v2/#swaggerObject). |
| transform | null | Transform method for the route's schema and url. [documentation](#register.options.transform). |
| transformObject | null | Transform method for the swagger or openapi object before it is rendered. [documentation](#register.options.transformObject). |
| refResolver | {} | Option to manage the `$ref`s of your application's schemas. Read the [`$ref` documentation](#register.options.refResolver) |
| exposeHeadRoutes | false | Include HEAD routes in the definitions |
| decorator | 'swagger' | Overrides the Fastify decorator. [documentation](#register.options.decorator). |

<a name="register.options.transform"></a>
#### Transform
Expand Down Expand Up @@ -362,6 +363,63 @@ await fastify.register(require('@fastify/swagger'), {

To deep down the `buildLocalReference` arguments, you may read the [documentation](https://github.com/Eomm/json-schema-resolver#usage-resolve-one-schema-against-external-schemas).

<a name="register.options.decorator"></a>
#### Decorator

By passing a string to the `decorator` option, you can override the default decorator function (`fastify.swagger()`) with a custom one. This allows you to create multiple documents by registering fastify-swagger multiple times with different `transform` functions:
Fdawgs marked this conversation as resolved.
Show resolved Hide resolved

```js
// Create an internal swagger doc
Fdawgs marked this conversation as resolved.
Show resolved Hide resolved
await fastify.register(require('@fastify/swagger'), {
swagger: { ... },
transform: ({ schema, url, route, swaggerObject }) => {
const {
params,
body,
querystring,
headers,
response,
...transformedSchema
} = schema
let transformedUrl = URL

// Hide external URLs
if (url.startsWith('/external')) transformedSchema.hide = true

return { schema: transformedSchema, url: transformedUrl }
},
decorator: 'internalSwagger'
})

// Create an external swagger doc
Fdawgs marked this conversation as resolved.
Show resolved Hide resolved
await fastify.register(require('@fastify/swagger'), {
swagger: { ... },
transform: ({ schema, url, route, swaggerObject }) => {
const {
params,
body,
querystring,
headers,
response,
...transformedSchema
} = schema
let transformedUrl = URL

// Hide internal URLs
if (url.startsWith('/internal')) transformedSchema.hide = true

return { schema: transformedSchema, url: transformedUrl }
},
decorator: 'externalSwagger'
})
```

You can then call those decorators individually to retrieve them:
```
fastify.internalSwagger()
fastify.externalSwagger()
```

<a name="route.options"></a>
### Route options

Expand Down
3 changes: 2 additions & 1 deletion lib/mode/dynamic.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = function (fastify, opts, done) {
swagger: {},
transform: null,
transformObject: null,
decorator: 'swagger',
refResolver: {
buildLocalReference (json, baseUri, fragment, i) {
if (!json.title && json.$id) {
Expand All @@ -31,7 +32,7 @@ module.exports = function (fastify, opts, done) {
}

const swagger = resolveSwaggerFunction(opts, cache, routes, Ref, done)
fastify.decorate('swagger', swagger)
fastify.decorate(opts.decorator, swagger)

done()
}
2 changes: 1 addition & 1 deletion lib/mode/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module.exports = function (fastify, opts, done) {
swaggerObject = opts.specification.document
}

fastify.decorate('swagger', swagger)
fastify.decorate(opts.decorator || 'swagger', swagger)

const cache = {
swaggerObject: null,
Expand Down
12 changes: 12 additions & 0 deletions test/decorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ test('fastify.swagger should throw if called before ready (openapi)', async (t)

t.throws(fastify.swagger.bind(fastify))
})

test('decorator can be overridden', async (t) => {
t.plan(1)
const fastify = Fastify()

await fastify.register(fastifySwagger, { decorator: 'customSwaggerDecorator' })

await fastify.ready()
mcollina marked this conversation as resolved.
Show resolved Hide resolved

await fastify.ready()
t.ok(fastify.customSwaggerDecorator())
})