Skip to content

Commit

Permalink
Merge pull request #3656 from boenrobot/prefixed-errors
Browse files Browse the repository at this point in the history
feature(http-adapter): added application's global prefix to error handlers and middleware
  • Loading branch information
kamilmysliwiec authored Jan 24, 2020
2 parents 5d1fdaf + 83c652c commit 5cca495
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 39 deletions.
76 changes: 76 additions & 0 deletions integration/hello-world/e2e/express-multiple.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { INestApplication } from '@nestjs/common';
import { ExpressAdapter } from '@nestjs/platform-express';
import { Test } from '@nestjs/testing';
import * as express from 'express';
import * as request from 'supertest';
import { ApplicationModule } from '../src/app.module';

describe('Hello world (express instance with multiple applications)', () => {
let server;
let apps: INestApplication[];

beforeEach(async () => {
const module1 = await Test.createTestingModule({
imports: [ApplicationModule],
}).compile();
const module2 = await Test.createTestingModule({
imports: [ApplicationModule],
}).compile();

const adapter = new ExpressAdapter(express());

apps = [
module1.createNestApplication(adapter),
module2.createNestApplication(adapter).setGlobalPrefix('/app2'),
];
await Promise.all(apps.map(app => app.init()));

server = adapter.getInstance();
});

it(`/GET`, () => {
return request(server)
.get('/hello')
.expect(200)
.expect('Hello world!');
});

it(`/GET (app2)`, () => {
return request(server)
.get('/app2/hello')
.expect(200)
.expect('Hello world!');
});

it(`/GET (Promise/async)`, () => {
return request(server)
.get('/hello/async')
.expect(200)
.expect('Hello world!');
});

it(`/GET (app2 Promise/async)`, () => {
return request(server)
.get('/app2/hello/async')
.expect(200)
.expect('Hello world!');
});

it(`/GET (Observable stream)`, () => {
return request(server)
.get('/hello/stream')
.expect(200)
.expect('Hello world!');
});

it(`/GET (app2 Observable stream)`, () => {
return request(server)
.get('/app2/hello/stream')
.expect(200)
.expect('Hello world!');
});

afterEach(async () => {
await Promise.all(apps.map(app => app.close()));
});
});
90 changes: 90 additions & 0 deletions integration/hello-world/e2e/fastify-multiple.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { Test } from '@nestjs/testing';
import { expect } from 'chai';
import { ApplicationModule } from '../src/app.module';

describe('Hello world (fastify adapter with multiple applications)', () => {
let adapter: FastifyAdapter;
let apps: NestFastifyApplication[];

beforeEach(async () => {
const module1 = await Test.createTestingModule({
imports: [ApplicationModule],
}).compile();
const module2 = await Test.createTestingModule({
imports: [ApplicationModule],
}).compile();

adapter = new FastifyAdapter();

apps = [
module1.createNestApplication<NestFastifyApplication>(adapter),
module2
.createNestApplication<NestFastifyApplication>(adapter)
.setGlobalPrefix('/app2'),
];
await Promise.all(apps.map(app => app.init()));
});

it(`/GET`, () => {
return adapter
.inject({
method: 'GET',
url: '/hello',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});

it(`/GET (app2)`, () => {
return adapter
.inject({
method: 'GET',
url: '/app2/hello',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});

it(`/GET (Promise/async)`, () => {
return adapter
.inject({
method: 'GET',
url: '/hello/async',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});

it(`/GET (app2 Promise/async)`, () => {
return adapter
.inject({
method: 'GET',
url: '/app2/hello/async',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});

it(`/GET (Observable stream)`, () => {
return adapter
.inject({
method: 'GET',
url: '/hello/stream',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});

it(`/GET (app2 Observable stream)`, () => {
return adapter
.inject({
method: 'GET',
url: '/app2/hello/stream',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});

afterEach(async () => {
await Promise.all(apps.map(app => app.close()));
await adapter.close();
});
});
8 changes: 4 additions & 4 deletions packages/common/interfaces/http/http-server.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export interface HttpServer<TRequest = any, TResponse = any> {
render(response: any, view: string, options: any): any;
redirect(response: any, statusCode: number, url: string): any;
setHeader(response: any, name: string, value: string): any;
setErrorHandler?(handler: Function): any;
setNotFoundHandler?(handler: Function): any;
setErrorHandler?(handler: Function, prefix?: string): any;
setNotFoundHandler?(handler: Function, prefix?: string): any;
useStaticAssets?(...args: any[]): this;
setBaseViewsDir?(path: string | string[]): this;
setViewEngine?(engineOrOptions: any): this;
Expand All @@ -58,8 +58,8 @@ export interface HttpServer<TRequest = any, TResponse = any> {
getRequestMethod?(request: TRequest): string;
getRequestUrl?(request: TResponse): string;
getInstance(): any;
registerParserMiddleware(): any;
enableCors(options: CorsOptions): any;
registerParserMiddleware(prefix?: string): any;
enableCors(options: CorsOptions, prefix?: string): any;
getHttpServer(): any;
initHttpServer(options: NestApplicationOptions): void;
close(): any;
Expand Down
2 changes: 1 addition & 1 deletion packages/common/interfaces/nest-application.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface INestApplication extends INestApplicationContext {
*
* @returns {void}
*/
enableCors(options?: CorsOptions): this;
enableCors(options?: CorsOptions): void;

/**
* Starts the application.
Expand Down
8 changes: 4 additions & 4 deletions packages/core/adapters/http-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ export abstract class AbstractHttpAdapter<
abstract reply(response, body: any, statusCode?: number);
abstract render(response, view: string, options: any);
abstract redirect(response, statusCode: number, url: string);
abstract setErrorHandler(handler: Function);
abstract setNotFoundHandler(handler: Function);
abstract setErrorHandler(handler: Function, prefix?: string);
abstract setNotFoundHandler(handler: Function, prefix?: string);
abstract setHeader(response, name: string, value: string);
abstract registerParserMiddleware();
abstract enableCors(options: CorsOptions);
abstract registerParserMiddleware(prefix?: string);
abstract enableCors(options: CorsOptions, prefix?: string);
abstract createMiddlewareFactory(
requestMethod: RequestMethod,
): (path: string, callback: Function) => any;
Expand Down
16 changes: 8 additions & 8 deletions packages/core/nest-application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export class NestApplication extends NestApplicationContext
) {
super(container);

this.applyOptions();
this.selectContextModule();
this.registerHttpServer();

Expand Down Expand Up @@ -106,7 +105,7 @@ export class NestApplication extends NestApplicationContext
if (!isCorsOptionsObj) {
return this.enableCors();
}
this.enableCors(this.appOptions.cors as CorsOptions);
return this.enableCors(this.appOptions.cors as CorsOptions);
}

public createServer<T = any>(): T {
Expand Down Expand Up @@ -137,9 +136,11 @@ export class NestApplication extends NestApplicationContext
}

public async init(): Promise<this> {
this.applyOptions();

const useBodyParser =
this.appOptions && this.appOptions.bodyParser !== false;
useBodyParser && this.registerParserMiddleware();
useBodyParser && this.registerParserMiddleware(this.config.getGlobalPrefix());

await this.registerModules();
await this.registerRouter();
Expand All @@ -152,8 +153,8 @@ export class NestApplication extends NestApplicationContext
return this;
}

public registerParserMiddleware() {
this.httpAdapter.registerParserMiddleware();
public registerParserMiddleware(prefix: string = '/') {
this.httpAdapter.registerParserMiddleware(prefix);
}

public async registerRouter() {
Expand Down Expand Up @@ -214,9 +215,8 @@ export class NestApplication extends NestApplicationContext
return this;
}

public enableCors(options?: CorsOptions): this {
this.httpAdapter.enableCors(options);
return this;
public enableCors(options?: CorsOptions): void {
this.httpAdapter.enableCors(options, this.config.getGlobalPrefix());
}

public async listen(
Expand Down
4 changes: 2 additions & 2 deletions packages/core/router/routes-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class RoutesResolver implements Resolver {
const handler = this.routerExceptionsFilter.create({}, callback, undefined);
const proxy = this.routerProxy.createProxy(callback, handler);
applicationRef.setNotFoundHandler &&
applicationRef.setNotFoundHandler(proxy);
applicationRef.setNotFoundHandler(proxy, this.config.getGlobalPrefix());
}

public registerExceptionHandler() {
Expand All @@ -105,7 +105,7 @@ export class RoutesResolver implements Resolver {
);
const proxy = this.routerProxy.createExceptionLayerProxy(callback, handler);
const applicationRef = this.container.getHttpAdapterRef();
applicationRef.setErrorHandler && applicationRef.setErrorHandler(proxy);
applicationRef.setErrorHandler && applicationRef.setErrorHandler(proxy, this.config.getGlobalPrefix());
}

public mapExternalException(err: any) {
Expand Down
8 changes: 4 additions & 4 deletions packages/core/test/utils/noop-adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export class NoopHttpAdapter extends AbstractHttpAdapter {
status(response: any, statusCode: number): any {}
render(response: any, view: string, options: any): any {}
redirect(response: any, statusCode: number, url: string) {}
setErrorHandler(handler: Function): any {}
setNotFoundHandler(handler: Function): any {}
setErrorHandler(handler: Function, prefix: string = '/'): any {}
setNotFoundHandler(handler: Function, prefix: string = '/'): any {}
setHeader(response: any, name: string, value: string): any {}
registerParserMiddleware(): any {}
enableCors(options: any): any {}
registerParserMiddleware(prefix: string = '/'): any {}
enableCors(options: any, prefix: string = '/'): any {}
createMiddlewareFactory(requestMethod: RequestMethod): any {}
getType() {
return '';
Expand Down
16 changes: 8 additions & 8 deletions packages/platform-express/adapters/express-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ export class ExpressAdapter extends AbstractHttpAdapter {
return response.redirect(statusCode, url);
}

public setErrorHandler(handler: Function) {
return this.use(handler);
public setErrorHandler(handler: Function, prefix: string = '/') {
return this.use(prefix, handler);
}

public setNotFoundHandler(handler: Function) {
return this.use(handler);
public setNotFoundHandler(handler: Function, prefix: string = '/') {
return this.use(prefix, handler);
}

public setHeader(response: any, name: string, value: string) {
Expand Down Expand Up @@ -104,8 +104,8 @@ export class ExpressAdapter extends AbstractHttpAdapter {
return request.url;
}

public enableCors(options: CorsOptions) {
this.use(cors(options));
public enableCors(options: CorsOptions, prefix: string = '/') {
return this.use(prefix, cors(options));
}

public createMiddlewareFactory(
Expand All @@ -128,14 +128,14 @@ export class ExpressAdapter extends AbstractHttpAdapter {
this.httpServer = http.createServer(this.getInstance());
}

public registerParserMiddleware() {
public registerParserMiddleware(prefix: string = '/') {
const parserMiddleware = {
jsonParser: bodyParser.json(),
urlencodedParser: bodyParser.urlencoded({ extended: true }),
};
Object.keys(parserMiddleware)
.filter(parser => !this.isMiddlewareApplied(parser))
.forEach(parserKey => this.use(parserMiddleware[parserKey]));
.forEach(parserKey => this.use(prefix, parserMiddleware[parserKey]));
}

public getType(): string {
Expand Down
Loading

0 comments on commit 5cca495

Please sign in to comment.