Skip to content

Commit 922bbc3

Browse files
committed
set http status code before running interceptors
added unit test and integration test changes http adapter to not send http status in reply
1 parent 20145b0 commit 922bbc3

12 files changed

Lines changed: 104 additions & 42 deletions

File tree

integration/hello-world/e2e/interceptors.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ export class TransformInterceptor {
2828
}
2929
}
3030

31+
@Injectable()
32+
export class StatusInterceptor {
33+
34+
constructor(private statusCode: number){}
35+
36+
intercept(context: ExecutionContext, next: CallHandler) {
37+
const ctx = context.switchToHttp();
38+
const res = ctx.getResponse();
39+
res.status(this.statusCode);
40+
return next.handle().pipe(map(data => ({ data })));
41+
}
42+
}
43+
3144
function createTestModule(interceptor) {
3245
return Test.createTestingModule({
3346
imports: [ApplicationModule],
@@ -87,6 +100,17 @@ describe('Interceptors', () => {
87100
.expect(200, { data: 'Hello world!' });
88101
});
89102

103+
it(`should modify response status`, async () => {
104+
app = (await createTestModule(
105+
new StatusInterceptor(400),
106+
)).createNestApplication();
107+
108+
await app.init();
109+
return request(app.getHttpServer())
110+
.get('/hello')
111+
.expect(400, { data: 'Hello world!' });
112+
});
113+
90114
afterEach(async () => {
91115
await app.close();
92116
});

integration/hello-world/src/hello/hello.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { HelloService } from './hello.service';
2-
import { Controller, Get, Header, Param } from '@nestjs/common';
2+
import { Controller, Get, Header, Param, Post } from '@nestjs/common';
33
import { Observable, of } from 'rxjs';
44
import { UserByIdPipe } from './users/user-by-id.pipe';
55

packages/common/interfaces/http/http-server.interface.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export interface HttpServer<TRequest = any, TResponse = any> {
4242
options(path: string, handler: RequestHandler<TRequest, TResponse>): any;
4343
listen(port: number | string, callback?: () => void): any;
4444
listen(port: number | string, hostname: string, callback?: () => void): any;
45-
reply(response: any, body: any, statusCode: number): any;
45+
reply(response: any, body: any): any;
46+
status(response: any, statusCode: number): any;
4647
render(response: any, view: string, options: any): any;
4748
setHeader(response: any, name: string, value: string): any;
4849
setErrorHandler?(handler: Function): any;

packages/core/adapters/http-adapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ export abstract class AbstractHttpAdapter<
8282
abstract setViewEngine(engine: string);
8383
abstract getRequestMethod(request);
8484
abstract getRequestUrl(request);
85-
abstract reply(response, body: any, statusCode: number);
85+
abstract status(response, statusCode: number);
86+
abstract reply(response, body: any);
8687
abstract render(response, view: string, options: any);
8788
abstract setErrorHandler(handler: Function);
8889
abstract setNotFoundHandler(handler: Function);

packages/core/exceptions/base-exception-filter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ export class BaseExceptionFilter<T = any> implements ExceptionFilter<T> {
3131
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
3232
message: MESSAGES.UNKNOWN_EXCEPTION_MESSAGE,
3333
};
34-
applicationRef.reply(host.getArgByIndex(1), body, body.statusCode);
34+
applicationRef.status(host.getArgByIndex(1), body.statusCode);
35+
applicationRef.reply(host.getArgByIndex(1), body);
3536
if (this.isExceptionObject(exception)) {
3637
return BaseExceptionFilter.logger.error(
3738
exception.message,
@@ -48,7 +49,8 @@ export class BaseExceptionFilter<T = any> implements ExceptionFilter<T> {
4849
message: res,
4950
};
5051

51-
applicationRef.reply(host.getArgByIndex(1), message, exception.getStatus());
52+
applicationRef.status(host.getArgByIndex(1), exception.getStatus());
53+
applicationRef.reply(host.getArgByIndex(1), message);
5254
}
5355

5456
public isExceptionObject(err: any): err is Error {

packages/core/router/router-execution-context.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class RouterExecutionContext {
8383
fnHandleResponse,
8484
paramtypes,
8585
getParamsMetadata,
86-
} = this.getMetadata(instance, callback, methodName, module, requestMethod);
86+
} = this.getMetadata(instance, callback, methodName, module);
8787
const paramsOptions = this.contextUtils.mergeParamsMetatypes(
8888
getParamsMetadata(module, contextId, inquirerId),
8989
paramtypes,
@@ -131,6 +131,14 @@ export class RouterExecutionContext {
131131
const args = this.contextUtils.createNullArray(argsLength);
132132
fnCanActivate && (await fnCanActivate([req, res]));
133133

134+
const httpCode = this.reflectHttpStatusCode(callback);
135+
136+
const httpStatusCode = httpCode
137+
? httpCode
138+
: this.responseController.getStatusByMethod(requestMethod);
139+
140+
this.responseController.status(res, httpStatusCode);
141+
134142
const result = await this.interceptorsConsumer.intercept(
135143
interceptors,
136144
[req, res],
@@ -146,8 +154,7 @@ export class RouterExecutionContext {
146154
instance: Controller,
147155
callback: (...args: any[]) => any,
148156
methodName: string,
149-
module: string,
150-
requestMethod: RequestMethod,
157+
module: string
151158
): HandlerMetadata {
152159
const cacheMetadata = this.handlerMetadataStorage.get(instance, methodName);
153160
if (cacheMetadata) {
@@ -165,7 +172,6 @@ export class RouterExecutionContext {
165172
instance,
166173
methodName,
167174
);
168-
const httpCode = this.reflectHttpStatusCode(callback);
169175
const getParamsMetadata = (
170176
moduleKey: string,
171177
contextId = STATIC_CONTEXT,
@@ -184,14 +190,10 @@ export class RouterExecutionContext {
184190
({ type }) =>
185191
type === RouteParamtypes.RESPONSE || type === RouteParamtypes.NEXT,
186192
);
187-
const httpStatusCode = httpCode
188-
? httpCode
189-
: this.responseController.getStatusByMethod(requestMethod);
190193

191194
const fnHandleResponse = this.createHandleResponseFn(
192195
callback,
193-
isResponseHandled,
194-
httpStatusCode,
196+
isResponseHandled
195197
);
196198
const handlerMetadata: HandlerMetadata = {
197199
argsLength,
@@ -341,8 +343,7 @@ export class RouterExecutionContext {
341343

342344
public createHandleResponseFn(
343345
callback: (...args: any[]) => any,
344-
isResponseHandled: boolean,
345-
httpStatusCode: number,
346+
isResponseHandled: boolean
346347
) {
347348
const renderTemplate = this.reflectRenderTemplate(callback);
348349
const responseHeaders = this.reflectResponseHeaders(callback);
@@ -358,10 +359,9 @@ export class RouterExecutionContext {
358359
return async <TResult, TResponse>(result: TResult, res: TResponse) => {
359360
hasCustomHeaders &&
360361
this.responseController.setHeaders(res, responseHeaders);
361-
362362
result = await this.responseController.transformToResult(result);
363363
!isResponseHandled &&
364-
(await this.responseController.apply(result, res, httpStatusCode));
364+
(await this.responseController.apply(result, res));
365365
};
366366
}
367367
}

packages/core/router/router-response-controller.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ export class RouterResponseController {
1111

1212
public async apply<TInput = any, TResponse = any>(
1313
result: TInput,
14-
response: TResponse,
15-
httpStatusCode: number,
14+
response: TResponse
1615
) {
17-
return this.applicationRef.reply(response, result, httpStatusCode);
16+
return this.applicationRef.reply(response, result);
1817
}
1918

2019
public async render<TInput = any, TResponse = any>(
@@ -50,4 +49,11 @@ export class RouterResponseController {
5049
this.applicationRef.setHeader(response, name, value),
5150
);
5251
}
52+
53+
public status<TResponse = any>(
54+
response: TResponse,
55+
statusCode: number
56+
) {
57+
this.applicationRef.status(response, statusCode);
58+
}
5359
}

packages/core/test/exceptions/exceptions-handler.spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ describe('ExceptionsHandler', () => {
3131

3232
describe('next', () => {
3333
beforeEach(() => {
34+
sinon
35+
.stub(adapter, 'status')
36+
.callsFake((responseRef: any, statusCode: number) => {
37+
return responseRef.status(statusCode);
38+
});
3439
sinon
3540
.stub(adapter, 'reply')
36-
.callsFake((responseRef: any, body: any, statusCode: number) => {
37-
const res = responseRef.status(statusCode);
41+
.callsFake((responseRef: any, body: any) => {
3842
if (isNil(body)) {
39-
return res.send();
43+
return responseRef.send();
4044
}
41-
return isObject(body) ? res.json(body) : res.send(String(body));
45+
return isObject(body) ? responseRef.json(body) : responseRef.send(String(body));
4246
});
4347
});
4448
it('should method send expected response status code and message when exception is unknown', () => {

packages/core/test/router/router-response-controller.spec.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,42 @@ describe('RouterResponseController', () => {
1818
describe('apply', () => {
1919
let response: {
2020
send: sinon.SinonSpy;
21-
status?: sinon.SinonSpy;
21+
status: sinon.SinonSpy;
2222
json: sinon.SinonSpy;
2323
};
2424
beforeEach(() => {
25-
response = { send: sinon.spy(), json: sinon.spy() };
26-
response.status = sinon.stub().returns(response);
25+
response = { send: sinon.spy(), json: sinon.spy(), status: sinon.spy() };
2726
});
2827
describe('when result is', () => {
2928
beforeEach(() => {
3029
sinon
3130
.stub(adapter, 'reply')
32-
.callsFake((responseRef: any, body: any, statusCode: number) => {
33-
const res = responseRef.status(statusCode);
31+
.callsFake((responseRef: any, body: any) => {
3432
if (isNil(body)) {
35-
return res.send();
33+
return responseRef.send();
3634
}
37-
return isObject(body) ? res.json(body) : res.send(String(body));
35+
return isObject(body) ? responseRef.json(body) : responseRef.send(String(body));
3836
});
3937
});
4038
describe('nil', () => {
4139
it('should call send()', async () => {
4240
const value = null;
43-
await routerResponseController.apply(value, response, 200);
41+
await routerResponseController.apply(value, response);
4442
expect(response.send.called).to.be.true;
4543
});
4644
});
4745
describe('string', () => {
4846
it('should call send(value)', async () => {
4947
const value = 'string';
50-
await routerResponseController.apply(value, response, 200);
48+
await routerResponseController.apply(value, response);
5149
expect(response.send.called).to.be.true;
5250
expect(response.send.calledWith(String(value))).to.be.true;
5351
});
5452
});
5553
describe('object', () => {
5654
it('should call json(value)', async () => {
5755
const value = { test: 'test' };
58-
await routerResponseController.apply(value, response, 200);
56+
await routerResponseController.apply(value, response);
5957
expect(response.json.called).to.be.true;
6058
expect(response.json.calledWith(value)).to.be.true;
6159
});
@@ -149,4 +147,22 @@ describe('RouterResponseController', () => {
149147
).to.be.true;
150148
});
151149
});
150+
151+
describe('status', () => {
152+
let statusStub: sinon.SinonStub;
153+
154+
beforeEach(() => {
155+
statusStub = sinon.stub(adapter, 'status').callsFake(() => ({}));
156+
});
157+
158+
it('should set status', () => {
159+
const response = {};
160+
const statusCode = 400;
161+
162+
routerResponseController.setStatus(response, statusCode);
163+
expect(
164+
statusStub.calledWith(response, statusCode),
165+
).to.be.true;
166+
});
167+
});
152168
});

packages/core/test/utils/noop-adapter.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export class NoopHttpAdapter extends AbstractHttpAdapter {
1111
setViewEngine(engine: string): any {}
1212
getRequestMethod(request: any): any {}
1313
getRequestUrl(request: any): any {}
14-
reply(response: any, body: any, statusCode: number): any {}
14+
reply(response: any, body: any): any {}
15+
status(response: any, statusCode: number): any {}
1516
render(response: any, view: string, options: any): any {}
1617
setErrorHandler(handler: Function): any {}
1718
setNotFoundHandler(handler: Function): any {}

0 commit comments

Comments
 (0)