Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
42 changes: 42 additions & 0 deletions docs/docs/common/openapi-and-swagger-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down Expand Up @@ -834,3 +835,44 @@ export class OpenApiController extends SwaggerController {
}

```

### Prevent automatic tag inheritance

In some use cases, it's useful to set tags on controllers but not have those tags be inherited by subcontrollers.

This allows organising routes in the Swagger UI and documentation under tags.

*Example*
```typescript
@ApiUseTag("Parent")
export class ApiController {
subControllers = [
controller('/sub1', SubController1),
controller('/sub2', SubController2)
]
}

@ApiUseTag("Sub1")
export class SubController1 {
/*
All routes (and sub rountes) in SubController1 will have two tags: "Parent", "Sub1"
*/
@Get("")
index() {
// ...
}
}

@ApiDisinheritTags()
@ApiUseTag("Sub2")
export class SubController2 {
/*
All rountes (and sub rountes) in SubController2 will have one tag: "Sub2"
*/
@Get("")
index() {
// ...
}
}
```

Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Using the `@ApiOperation` decorator can sometimes be cumbersome. That is why Foa
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Beside the `@ApiOperation` decorator, you can also use other decorators more spe
| `@ApiDefineTag` |
| `@ApiExternalDoc` |
| `@ApiUseTag` |
| `@ApiDisinheritTags` |
| `@ApiParameter` |
| `@ApiResponse` |
| `@ApiCallback` |
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/core/openapi/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function AddMetadataItem<T>(metadataKey: string, item: T) {
return (target: any, propertyKey?: string) => {
// Note that propertyKey can be undefined as it's an optional parameter in getMetadata.
let items: T[] = Reflect.getMetadata(metadataKey, target, propertyKey as string) || [];
items = [ item, ...items ];
items = [item, ...items];
Reflect.defineMetadata(metadataKey, items, target, propertyKey as string);
};
}
Expand Down Expand Up @@ -74,6 +74,10 @@ export function ApiUseTag(tag: string | ((controller: any) => string)): OpenApiD
return AddMetadataItem('api:operation:tags', tag);
}

export function ApiDisinheritTags(disinheritTags: boolean = true): OpenApiDecorator {
return Reflect.metadata('api:operation:disinheritTags', disinheritTags);
}

export function ApiParameter(
parameter: IApiParameter | IApiReference | ((controller: any) => IApiParameter | IApiReference)
): OpenApiDecorator {
Expand All @@ -87,7 +91,7 @@ export function ApiRequestBody(
}

export function ApiResponse(
key: 'default'|'1XX'|'2XX'|'3XX'|'4XX'|'5XX'|number,
key: 'default' | '1XX' | '2XX' | '3XX' | '4XX' | '5XX' | number,
response: IApiResponse | IApiReference | ((controller: any) => IApiResponse | IApiReference)
): OpenApiDecorator {
return AddMetadataProperty('api:operation:responses', key.toString(), response);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// std
import { deepStrictEqual, strictEqual } from 'assert';

// FoalTS
import { ApiDisinheritTags } from '../decorators';
import { getApiDisinheritTags } from './get-api-disinherit-tags';

describe('getApiInfo', () => {


describe('when an api information is defined, should return it', () => {

it('from a class.', () => {
@ApiDisinheritTags()
class Controller { }

const actual = getApiDisinheritTags(Controller);

deepStrictEqual(actual, true);
});

});

describe('when no api information is defined, should return undefined', () => {

it('from a class.', () => {
class Controller { }

const actual = getApiDisinheritTags(Controller);

strictEqual(actual, undefined);
});

});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Class } from '../../class.interface';
import { getMetadata } from '../../routes/utils';

export function getApiDisinheritTags(
controllerClass: Class, propertyKey?: string
): boolean | undefined {
return getMetadata('api:operation:disinheritTags', controllerClass, propertyKey);
}
47 changes: 32 additions & 15 deletions packages/core/src/core/openapi/utils/merge-operations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ describe('mergeOperations', () => {
};
const operation2: IApiOperation = {
responses: {},
tags: [ 'tag1' ]
tags: ['tag1']
};

const operation = mergeOperations(operation1, operation2);

deepStrictEqual(operation, {
responses: {},
tags: [ 'tag1' ]
tags: ['tag1']
});
});

it('when operation2.tags is undefined and operation1.tags is not.', () => {
const operation1: IApiOperation = {
responses: {},
tags: [ 'tag1' ]
tags: ['tag1']
};
const operation2: IApiOperation = {
responses: {}
Expand All @@ -36,7 +36,7 @@ describe('mergeOperations', () => {

deepStrictEqual(operation, {
responses: {},
tags: [ 'tag1' ]
tags: ['tag1']
});
});

Expand All @@ -58,21 +58,38 @@ describe('mergeOperations', () => {
it('when both operation1.tags and operation2.tags are defined.', () => {
const operation1: IApiOperation = {
responses: {},
tags: [ 'tag1' ]
tags: ['tag1']
};
const operation2: IApiOperation = {
responses: {},
tags: [ 'tag2' ]
tags: ['tag2']
};

const operation = mergeOperations(operation1, operation2);

deepStrictEqual(operation, {
responses: {},
tags: [ 'tag1', 'tag2' ]
tags: ['tag1', 'tag2']
});
});

it('when both operation1.tags and operation2.tags are defined but disinheritTags is true.', () => {
const operation1: IApiOperation = {
responses: {},
tags: ['tag1']
};
const operation2: IApiOperation = {
responses: {},
tags: ['tag2']
};

const operation = mergeOperations(operation1, operation2, true);

deepStrictEqual(operation, {
responses: {},
tags: ['tag2']
});
});
});

describe('should merge the summary', () => {
Expand Down Expand Up @@ -776,7 +793,7 @@ describe('mergeOperations', () => {
responses: {},
security: [
{
a: [ 'a1' ]
a: ['a1']
}
],
};
Expand All @@ -787,7 +804,7 @@ describe('mergeOperations', () => {
responses: {},
security: [
{
a: [ 'a1' ]
a: ['a1']
}
],
});
Expand All @@ -798,7 +815,7 @@ describe('mergeOperations', () => {
responses: {},
security: [
{
a: [ 'a1' ]
a: ['a1']
}
],
};
Expand All @@ -812,7 +829,7 @@ describe('mergeOperations', () => {
responses: {},
security: [
{
a: [ 'a1' ]
a: ['a1']
}
],
});
Expand All @@ -838,15 +855,15 @@ describe('mergeOperations', () => {
responses: {},
security: [
{
a: [ 'a1' ]
a: ['a1']
}
],
};
const operation2: IApiOperation = {
responses: {},
security: [
{
b: [ 'b1' ]
b: ['b1']
}
],
};
Expand All @@ -857,10 +874,10 @@ describe('mergeOperations', () => {
responses: {},
security: [
{
a: [ 'a1' ]
a: ['a1']
},
{
b: [ 'b1' ]
b: ['b1']
}
],
});
Expand Down
Loading