diff --git a/packages/openapi-v2/src/controller-spec.ts b/packages/openapi-v2/src/controller-spec.ts index 608b3e95b848..647574701105 100644 --- a/packages/openapi-v2/src/controller-spec.ts +++ b/packages/openapi-v2/src/controller-spec.ts @@ -247,6 +247,18 @@ export function del(path: string, spec?: OperationObject) { return operation('delete', path, spec); } +/** + * Expose a Controller method as a REST API operation + * mapped to `HEAD` request method. + * + * @param path The URL path of this operation, e.g. `/product/{id}` + * @param spec The OpenAPI specification describing parameters and responses + * of this operation. + */ +export function head(path: string, spec?: OperationObject) { + return operation('head', path, spec); +} + /** * Expose a Controller method as a REST API operation. * diff --git a/packages/openapi-v2/test/unit/controller-spec/controller-decorators.test.ts b/packages/openapi-v2/test/unit/controller-spec/controller-decorators.test.ts index c7ac4dc164fc..738813132432 100644 --- a/packages/openapi-v2/test/unit/controller-spec/controller-decorators.test.ts +++ b/packages/openapi-v2/test/unit/controller-spec/controller-decorators.test.ts @@ -12,6 +12,7 @@ import { put, patch, del, + head, param, } from '../../..'; import {expect} from '@loopback/testlab'; @@ -52,9 +53,7 @@ describe('Routing metadata', () => { }); it('returns spec defined via @get decorator', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class MyController { @get('/greet', operationSpec) @@ -78,9 +77,7 @@ describe('Routing metadata', () => { }); it('returns spec defined via @post decorator', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class MyController { @post('/greeting', operationSpec) @@ -102,9 +99,7 @@ describe('Routing metadata', () => { }); it('returns spec defined via @put decorator', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class MyController { @put('/greeting', operationSpec) @@ -126,9 +121,7 @@ describe('Routing metadata', () => { }); it('returns spec defined via @patch decorator', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class MyController { @patch('/greeting', operationSpec) @@ -150,9 +143,7 @@ describe('Routing metadata', () => { }); it('returns spec defined via @del decorator', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class MyController { @del('/greeting', operationSpec) @@ -173,10 +164,32 @@ describe('Routing metadata', () => { }); }); + it('returns spec defined via @head decorator', () => { + const operationSpec = givenAnOperationSpec(); + + class MyController { + @head('/greeting', operationSpec) + greet() { + return 'Hello world!'; + } + } + + const actualSpec = getControllerSpec(MyController); + + expect(actualSpec).to.eql({ + paths: { + '/greeting': { + head: { + 'x-operation-name': 'greet', + ...operationSpec, + }, + }, + }, + }); + }); + it('returns spec defined via @operation decorator', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class MyController { @operation('post', '/greeting', operationSpec) @@ -265,9 +278,7 @@ describe('Routing metadata', () => { }); it('allows children to override parent REST endpoints', () => { - const operationSpec = anOperationSpec() - .withStringResponse() - .build(); + const operationSpec = givenAnOperationSpec(); class Parent { @get('/name', operationSpec) @@ -371,4 +382,10 @@ describe('Routing metadata', () => { in: 'query', }); }); + + function givenAnOperationSpec() { + return anOperationSpec() + .withStringResponse() + .build(); + } });