nestjs-openapi-next
v1.0.4
Published
A fork of @nestjs/swagger support OAS 3.2
Readme
nestjs-openapi-next
nestjs-openapi-next is a fork of @nestjs/swagger (upstream: nestjs/swagger).
The goal is to keep upstream behavior as compatible as possible while adding a set of OpenAPI 3.1/3.2 features and widely-used OpenAPI extension fields (x-) that are commonly consumed by tools like Redoc.
Key differences from upstream
- Richer OpenAPI 3.1/3.2 typings
- e.g.
TagObject.summary,OAuthFlowsObject.deviceAuthorization,LicenseObject.identifier, etc.
- e.g.
- Enhanced tag support
@ApiTag(options)(class/controller-level): defines tag metadata (summary,x-displayName,description,parent,kind, ...) and merges it into the top-leveldocument.tags.x-displayNamesupport for tags, mirrored withsummary(setting either results in both fields being written with the same value).- Root-level
x-tagGroupssupport (commonly used by Redoc). If you useparentto form relationships,x-tagGroupsis auto-derived; you can also set it explicitly viaDocumentBuilder.
- OAS 3.1 features
- JSON Schema Draft 2020-12 alignment (e.g.
$defs,prefixItems,const,contentEncoding,contentMediaType,contentSchema). typeas array support (e.g.type: ['string', 'null']) with automaticnullableremoval.LicenseObject.identifierfield support viaDocumentBuilder.setLicense().ReferenceObjectwithsummaryanddescriptionoverride support.exclusiveMinimum/exclusiveMaximumas number type (changed from boolean in OAS 3.0).
- JSON Schema Draft 2020-12 alignment (e.g.
- OAS 3.2 features
- HTTP
QUERYmethod via@ApiQueryMethod()(emitspaths['/x'].query). - Streaming responses via
@ApiStreamingResponse()(itemSchema, e.g. SSEtext/event-stream). - OAuth2 Device Authorization Flow typing +
@ApiSecurityDeviceFlow()helper. ServerObject.pathPrefixfield support viaDocumentBuilder.addServer().InfoObject.tagsfield support viaDocumentBuilder.setInfoTags().
- HTTP
- Convenience APIs
DocumentBuilder.addServerWithName()for a non-standard-but-commonserver.name.
Test coverage: test/openapi-3-1.spec.ts, test/openapi-3-2.spec.ts.
Compatibility
- NestJS: peerDependencies target
@nestjs/common/@nestjs/core^11.0.1 - Runtime deps: aligned with upstream
@nestjs/swagger(reflect-metadata, optionalclass-validator/class-transformer, etc.)
Installation
Install from npm
npm i --save nestjs-openapi-nextQuick start (same as upstream)
See the official Nest OpenAPI tutorial: https://docs.nestjs.com/openapi/introduction
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from 'nestjs-openapi-next';
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('Example')
.setDescription('API description')
.setVersion('1.0')
// If you want the document to declare OAS 3.2, set it explicitly:
.setOpenAPIVersion('3.2.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);Usage
1) @ApiTag(options) (recommended) and deprecation of @ApiTagGroup()
@ApiTag(options) is the primary decorator for defining tag metadata at the controller level.
@ApiTagGroup(options) is kept as a backward-compatible alias, but is deprecated and may be removed in a future major version.
import { Controller, Get } from '@nestjs/common';
import { ApiTag } from 'nestjs-openapi-next';
@ApiTag({
name: 'Customers',
summary: 'Customers'
// you may also set: 'x-displayName': 'Customers'
})
@Controller('customers')
export class CustomersController {
@Get()
list() {
return [];
}
}2) Tag x-displayName (mirrored with summary)
This fork treats tag summary and x-displayName as equivalent display fields:
- set either one;
- the generated
document.tagswill contain bothsummaryandx-displayNamewith the same value.
3) Root-level x-tagGroups (tag grouping)
Auto-derived (recommended)
If you use tag parent relationships (via @ApiTag()), the root-level x-tagGroups will be derived automatically (both in the scanned output and in the final document), so downstream generators (e.g. .tags) can render grouped tags correctly:
@ApiTag({ name: 'Customers' })
@Controller('customers')
export class CustomersController {}
@ApiTag({ name: 'Customer Authentication', parent: 'Customers' })
@Controller('auth')
export class AuthController {}Illustrative output:
tags:
- name: Customers
- name: Customer Authentication
x-tagGroups:
- name: Customers
tags:
- Customers
- Customer AuthenticationManual configuration
You can also set x-tagGroups explicitly via DocumentBuilder.addTagGroup():
const config = new DocumentBuilder()
.setTitle('t')
.setVersion('1')
.addTag('Customers')
.addTag('Customer Authentication')
.addTagGroup('Customers', ['Customers', 'Customer Authentication'])
.build();4) HTTP QUERY method: @ApiQueryMethod()
import { Controller, Post } from '@nestjs/common';
import { ApiQueryMethod } from 'nestjs-openapi-next';
@Controller()
export class QueryController {
@Post('search')
@ApiQueryMethod()
search() {
return { ok: true };
}
}5) Streaming responses: @ApiStreamingResponse() (itemSchema)
import { Controller, Get } from '@nestjs/common';
import { ApiProperty, ApiStreamingResponse } from 'nestjs-openapi-next';
class SseItemDto {
@ApiProperty()
id: string;
}
@Controller()
export class EventsController {
@Get('events')
@ApiStreamingResponse({
status: 200,
contentType: 'text/event-stream',
type: () => SseItemDto
})
stream() {
return null;
}
}6) OAuth2 Device Authorization Flow: flows.deviceAuthorization + @ApiSecurityDeviceFlow()
import { Controller, Get } from '@nestjs/common';
import { ApiSecurityDeviceFlow, DocumentBuilder } from 'nestjs-openapi-next';
@Controller()
export class SecuredController {
@Get('secure')
@ApiSecurityDeviceFlow('oauth2', ['read'])
secure() {
return { ok: true };
}
}
const config = new DocumentBuilder()
.setTitle('t')
.setVersion('1')
.addOAuth2(
{
type: 'oauth2',
flows: {
deviceAuthorization: {
deviceAuthorizationUrl: 'https://example.com/device',
tokenUrl: 'https://example.com/token',
scopes: { read: 'Read access' }
}
}
},
'oauth2'
)
.build();7) OpenAPI 3.1 Webhooks: @ApiWebhook()
OpenAPI 3.1 introduces a root-level webhooks object for out-of-band callbacks
initiated by the API provider.
This fork supports emitting webhook operations via a decorator:
import { Controller, Post } from '@nestjs/common';
import { ApiWebhook } from '@nestjs/swagger';
@Controller()
export class StripeWebhooksController {
@Post('stripe')
@ApiWebhook('stripeEvent')
stripe() {
return { ok: true };
}
}The generated document will contain document.webhooks.stripeEvent.post, and the
corresponding route will not be emitted under document.paths.
8) LicenseObject.identifier (OAS 3.1)
OAS 3.1 added an identifier field to LicenseObject for SPDX license identifiers:
const config = new DocumentBuilder()
.setTitle('Example')
.setVersion('1.0')
.setLicense('MIT', 'https://opensource.org/licenses/MIT', 'MIT')
.build();This produces:
info:
license:
name: MIT
url: https://opensource.org/licenses/MIT
identifier: MIT9) ServerObject.pathPrefix (OAS 3.2)
OAS 3.2 added a pathPrefix field to ServerObject:
const config = new DocumentBuilder()
.setTitle('Example')
.setVersion('1.0')
.addServer('https://api.example.com', 'Production', {}, '/v1')
.build();This produces:
servers:
- url: https://api.example.com
description: Production
pathPrefix: /v110) InfoObject.tags (OAS 3.2)
OAS 3.2 added a tags field to InfoObject for categorizing the API itself:
const config = new DocumentBuilder()
.setTitle('Example')
.setVersion('1.0')
.setInfoTags(['payments', 'commerce'])
.build();This produces:
info:
title: Example
version: '1.0'
tags:
- payments
- commerce11) ReferenceObject with summary / description override (OAS 3.1)
OAS 3.1 allows $ref objects to include summary and description fields that override the referenced schema's values:
import { ApiProperty } from 'nestjs-openapi-next';
class CreateUserDto {
@ApiProperty({
allOf: [
{
$ref: '#/components/schemas/BaseUser',
summary: 'User base fields',
description: 'Contains the common user properties'
}
]
})
user: BaseUser;
}12) type as array (OAS 3.1)
OAS 3.1 supports type as an array for union types. This replaces the nullable keyword:
import { ApiProperty } from 'nestjs-openapi-next';
class UserDto {
@ApiProperty({ type: ['string', 'null'] })
nickname: string | null;
}This produces type: ['string', 'null'] instead of type: 'string', nullable: true.
13) JSON Schema Draft 2020-12 keywords (OAS 3.1)
OAS 3.1 aligns with JSON Schema Draft 2020-12, adding support for:
$defs- local schema definitionsprefixItems- tuple validation (replacesitemsarray form)const- exact value matchingcontentEncoding- encoding for string content (e.g.,base64)contentMediaType- media type for string contentcontentSchema- schema for decoded content
import { ApiProperty } from 'nestjs-openapi-next';
class FileDto {
@ApiProperty({
contentEncoding: 'base64',
contentMediaType: 'image/png'
})
data: string;
}License
MIT (see LICENSE). This repository is a derivative work of the upstream nestjs/swagger project under the MIT license.
