feature() extract fastify, multer, cors, adapters

This commit is contained in:
Kamil Myśliwiec
2018-12-01 21:02:36 +01:00
parent bc4a8a556c
commit a3fbb8816e
47 changed files with 305 additions and 205 deletions

View File

@@ -12,6 +12,12 @@ const packages = {
microservices: ts.createProject('packages/microservices/tsconfig.json'),
websockets: ts.createProject('packages/websockets/tsconfig.json'),
testing: ts.createProject('packages/testing/tsconfig.json'),
'platform-express': ts.createProject(
'packages/platform-express/tsconfig.json',
),
'platform-fastify': ts.createProject(
'packages/platform-fastify/tsconfig.json',
),
};
const modules = Object.keys(packages);
const source = 'packages';
@@ -34,7 +40,9 @@ gulp.task('copy-misc', function() {
.pipe(gulp.dest(`${source}/core`))
.pipe(gulp.dest(`${source}/microservices`))
.pipe(gulp.dest(`${source}/websockets`))
.pipe(gulp.dest(`${source}/testing`));
.pipe(gulp.dest(`${source}/testing`))
.pipe(gulp.dest(`${source}/platform-fastify`))
.pipe(gulp.dest(`${source}/platform-express`));
});
gulp.task('clean:output', function() {

35
package-lock.json generated
View File

@@ -4972,6 +4972,30 @@
}
}
},
"fastify-cors": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-0.2.0.tgz",
"integrity": "sha512-bw14FmjHm8oF4TDLkwj2TpssH6O2gE0NpsRqLe7F1Gh9Jf30Lx9ZzIznhqaAKOYS+LJqLIt5snurv7urgqYntA==",
"requires": {
"fastify-plugin": "^1.2.0",
"vary": "^1.1.2"
},
"dependencies": {
"fastify-plugin": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-1.2.1.tgz",
"integrity": "sha512-TLmXpp3PEsD3MFSV3FBiH70hkalvgZ8Qmg3hr1FcJpZFaPwxoWUDoFdXZrguY+2gBVQgkFtrM47aWL5lNHqg+Q==",
"requires": {
"semver": "^5.5.0"
}
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
}
}
},
"fastify-formbody": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fastify-formbody/-/fastify-formbody-2.0.0.tgz",
@@ -8467,6 +8491,11 @@
"sshpk": "^1.7.0"
}
},
"http2": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz",
"integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ=="
},
"husky": {
"version": "0.14.3",
"resolved": "https://registry.npmjs.org/husky/-/husky-0.14.3.tgz",
@@ -13420,9 +13449,9 @@
"dev": true
},
"prettier": {
"version": "1.10.2",
"resolved": "http://192.168.228.42:5000/prettier/-/prettier-1.10.2.tgz",
"integrity": "sha512-TcdNoQIWFoHblurqqU6d1ysopjq7UX0oRcT/hJ8qvBAELiYWn+Ugf0AXdnzISEJ7vuhNnQ98N8jR8Sh53x4IZg==",
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.15.3.tgz",
"integrity": "sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg==",
"dev": true
},
"pretty-format": {

View File

@@ -5,21 +5,30 @@
"scripts": {
"coverage": "nyc report --reporter=text-lcov | coveralls",
"precommit": "lint-staged",
"test": "nyc --require ts-node/register mocha packages/**/*.spec.ts --reporter spec --require 'node_modules/reflect-metadata/Reflect.js'",
"integration-test": "mocha integration/**/*.spec.ts --reporter spec --require ts-node/register --require 'node_modules/reflect-metadata/Reflect.js'",
"lint": "tslint -p tsconfig.json -c tslint.json \"packages/**/*.ts\" -e \"*.spec.ts\"",
"format": "prettier **/**/*.ts --ignore-path ./.prettierignore --write && git status",
"test":
"nyc --require ts-node/register mocha packages/**/*.spec.ts --reporter spec --require 'node_modules/reflect-metadata/Reflect.js'",
"integration-test":
"mocha integration/**/*.spec.ts --reporter spec --require ts-node/register --require 'node_modules/reflect-metadata/Reflect.js'",
"lint":
"tslint -p tsconfig.json -c tslint.json \"packages/**/*.ts\" -e \"*.spec.ts\"",
"format":
"prettier **/**/*.ts --ignore-path ./.prettierignore --write && git status",
"clean": "gulp clean:bundle",
"build": "npm run clean && gulp build",
"prebuild:dev": "rm -rf node_modules/@nestjs",
"build:dev": "gulp build --dist node_modules/@nestjs && gulp move",
"postinstall": "opencollective",
"prerelease": "gulp copy-misc && gulp build --dist node_modules/@nestjs",
"publish": "npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --force-publish --exact -m \"chore(@nestjs) publish %s release\"",
"publish:rc": "npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --npm-tag=rc -m \"chore(@nestjs) publish %s release\"",
"publish:next": "npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --npm-tag=next --skip-git -m \"chore(@nestjs) publish %s release\"",
"publish:beta": "npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --npm-tag=beta -m \"chore(@nestjs) publish %s release\"",
"publish:test": "npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --force-publish --npm-tag=test --skip-git -m \"chore(@nestjs) publish %s release\""
"publish":
"npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --force-publish --exact -m \"chore(@nestjs) publish %s release\"",
"publish:rc":
"npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --npm-tag=rc -m \"chore(@nestjs) publish %s release\"",
"publish:next":
"npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --npm-tag=next --skip-git -m \"chore(@nestjs) publish %s release\"",
"publish:beta":
"npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --npm-tag=beta -m \"chore(@nestjs) publish %s release\"",
"publish:test":
"npm run prerelease && npm run build && ./node_modules/.bin/lerna publish --force-publish --npm-tag=test --skip-git -m \"chore(@nestjs) publish %s release\""
},
"engines": {
"node": ">= 8.9.0"
@@ -52,9 +61,11 @@
"fast-json-stringify": "^1.5.4",
"fast-safe-stringify": "^1.2.0",
"fastify": "^1.1.1",
"fastify-cors": "^0.2.0",
"fastify-formbody": "^2.0.0",
"fastify-multipart": "^0.4.1",
"grpc": "^1.14.1",
"http2": "^3.3.7",
"iterare": "0.0.8",
"json-socket": "^0.2.1",
"mqtt": "^2.16.0",
@@ -114,7 +125,7 @@
"mocha": "^3.2.0",
"nodemon": "^1.18.4",
"nyc": "^10.1.2",
"prettier": "^1.9.2",
"prettier": "^1.15.3",
"sinon": "^2.1.0",
"sinon-chai": "^2.8.0",
"socket.io-client": "^2.0.4",
@@ -131,14 +142,11 @@
}
},
"nyc": {
"include": [
"packages/**/*.ts"
],
"include": ["packages/**/*.ts"],
"exclude": [
"node_modules/",
"packages/**/*.spec.ts",
"packages/core/adapters/*.ts",
"packages/websockets/adapters/*.ts",
"packages/**/adapters/*.ts",
"packages/**/nest-*.ts",
"packages/core/errors/**/*",
"packages/common/exceptions/*.ts",
@@ -153,23 +161,13 @@
"packages/common/serializer/**/*",
"packages/common/services/logger.service.ts"
],
"extension": [
".ts"
],
"require": [
"ts-node/register"
],
"reporter": [
"text-summary",
"html"
],
"extension": [".ts"],
"require": ["ts-node/register"],
"reporter": ["text-summary", "html"],
"sourceMap": true,
"instrument": true
},
"lint-staged": {
"packages/**/*.{ts,json}": [
"npm run format",
"git add"
]
"packages/**/*.{ts,json}": ["npm run format", "git add"]
}
}

View File

@@ -10,7 +10,6 @@ export * from './cache';
export * from './decorators';
export * from './enums';
export * from './exceptions';
export * from './files';
export * from './http';
export {
ArgumentMetadata,
@@ -42,5 +41,5 @@ export {
} from './interfaces';
export * from './pipes';
export * from './serializer';
export * from './services/logger.service';
export * from './services';
export * from './utils';

View File

@@ -1,4 +1,5 @@
import { RequestMethod } from '../../enums';
import { CorsOptions } from './../../interfaces/external/cors-options.interface';
import { NestApplicationOptions } from './../../interfaces/nest-application-options.interface';
export type ErrorHandler<TRequest = any, TResponse = any> = (
@@ -56,6 +57,7 @@ export interface HttpServer<TRequest = any, TResponse = any> {
getRequestUrl?(request: TResponse): string;
getInstance(): any;
registerParserMiddleware(): any;
enableCors(options: CorsOptions): any;
getHttpServer(): any;
initHttpServer(options: NestApplicationOptions): void;
close(): any;

View File

@@ -1,7 +1,8 @@
{
"name": "@nestjs/common",
"version": "5.4.1",
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
"description":
"Nest - modern, fast, powerful node.js web framework (@common)",
"author": "Kamil Mysliwiec",
"repository": {
"type": "git",
@@ -11,7 +12,6 @@
"dependencies": {
"axios": "0.18.0",
"cli-color": "1.2.0",
"multer": "1.3.0",
"uuid": "3.3.2"
},
"peerDependencies": {

View File

@@ -0,0 +1 @@
export * from './logger.service';

View File

@@ -1,5 +1,6 @@
import { HttpServer, RequestMethod } from '@nestjs/common';
import { RequestHandler } from '@nestjs/common/interfaces';
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
export abstract class AbstractHttpAdapter<T = any> implements HttpServer {
@@ -73,8 +74,7 @@ export abstract class AbstractHttpAdapter<T = any> implements HttpServer {
abstract close();
abstract initHttpServer(options: NestApplicationOptions);
abstract useStaticAssets(path: string, options: any);
abstract setBaseViewsDir(path: string);
abstract useStaticAssets(...args: any[]);
abstract setViewEngine(engine: string);
abstract getRequestMethod(request);
abstract getRequestUrl(request);
@@ -84,6 +84,7 @@ export abstract class AbstractHttpAdapter<T = any> implements HttpServer {
abstract setNotFoundHandler(handler: Function);
abstract setHeader(response, name: string, value: string);
abstract registerParserMiddleware();
abstract enableCors(options: CorsOptions);
abstract createMiddlewareFactory(
requestMethod: RequestMethod,
): (path: string, callback: Function) => any;

View File

@@ -21,8 +21,8 @@ export class NestApplicationContext implements INestApplicationContext {
constructor(
protected readonly container: NestContainer,
private readonly scope: Type<any>[],
private contextModule: Module,
private readonly scope: Type<any>[] = [],
private contextModule: Module = null,
) {
this.containerScanner = new ContainerScanner(container);
}

View File

@@ -14,7 +14,6 @@ import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-applicati
import { Logger } from '@nestjs/common/services/logger.service';
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { isObject, validatePath } from '@nestjs/common/utils/shared.utils';
import * as cors from 'cors';
import { Server } from 'http';
import { Server as HttpsServer } from 'https';
import iterate from 'iterare';
@@ -55,7 +54,7 @@ export class NestApplication extends NestApplicationContext
private readonly config: ApplicationConfig,
private readonly appOptions: NestApplicationOptions = {},
) {
super(container, [], null);
super(container);
this.applyOptions();
this.selectContextModule();
@@ -90,9 +89,9 @@ export class NestApplication extends NestApplicationContext
this.enableCors(this.appOptions.cors as CorsOptions);
}
public createServer(): any {
public createServer<T = any>(): T {
this.httpAdapter.initHttpServer(this.appOptions);
return this.httpAdapter.getHttpServer();
return this.httpAdapter.getHttpServer() as T;
}
public async registerModules() {
@@ -188,7 +187,7 @@ export class NestApplication extends NestApplicationContext
}
public enableCors(options?: CorsOptions): this {
this.httpAdapter.use(cors(options) as any);
this.httpAdapter.enableCors(options);
return this;
}
@@ -276,8 +275,8 @@ export class NestApplication extends NestApplicationContext
return this;
}
private loadPackage(name: string, ctx: string) {
return loadPackage(name, ctx);
private loadPackage<T = any>(name: string, ctx: string): T {
return loadPackage(name, ctx) as T;
}
private async registerMiddleware(instance: any) {

View File

@@ -20,12 +20,10 @@
},
"dependencies": {
"@nuxtjs/opencollective": "0.1.0",
"cors": "2.8.4",
"fast-safe-stringify": "1.2.0",
"iterare": "0.0.8",
"object-hash": "1.3.0",
"optional": "0.1.4",
"path-to-regexp": "2.2.1",
"uuid": "3.3.2"
},
"peerDependencies": {

View File

@@ -1,14 +1,17 @@
import { HttpException } from '@nestjs/common';
import { isNil, isObject } from '@nestjs/common/utils/shared.utils';
import { expect } from 'chai';
import * as sinon from 'sinon';
import { NestEnvironment } from '../../../common/enums/nest-environment.enum';
import { Logger } from '../../../common/services/logger.service';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { AbstractHttpAdapter } from '../../adapters';
import { InvalidExceptionFilterException } from '../../errors/exceptions/invalid-exception-filter.exception';
import { ExceptionsHandler } from '../../exceptions/exceptions-handler';
import { ExecutionContextHost } from '../../helpers/execution-context.host';
import { NoopHttpAdapter } from './../utils/noop-adapter';
describe('ExceptionsHandler', () => {
let adapter: AbstractHttpAdapter;
let handler: ExceptionsHandler;
let statusStub: sinon.SinonStub;
let jsonStub: sinon.SinonStub;
@@ -17,7 +20,8 @@ describe('ExceptionsHandler', () => {
before(() => Logger.setMode(NestEnvironment.TEST));
beforeEach(() => {
handler = new ExceptionsHandler(new ExpressAdapter({}));
adapter = new NoopHttpAdapter({});
handler = new ExceptionsHandler(adapter);
statusStub = sinon.stub();
jsonStub = sinon.stub();
@@ -30,6 +34,17 @@ describe('ExceptionsHandler', () => {
});
describe('next', () => {
beforeEach(() => {
sinon
.stub(adapter, 'reply')
.callsFake((responseRef: any, body: any, statusCode: number) => {
const res = responseRef.status(statusCode);
if (isNil(body)) {
return res.send();
}
return isObject(body) ? res.json(body) : res.send(String(body));
});
});
it('should method send expected response status code and message when exception is unknown', () => {
handler.next(new Error(), new ExecutionContextHost([0, response]));

View File

@@ -5,7 +5,6 @@ import { Controller } from '../../../common/decorators/core/controller.decorator
import { RequestMapping } from '../../../common/decorators/http/request-mapping.decorator';
import { RequestMethod } from '../../../common/enums/request-method.enum';
import { NestMiddleware } from '../../../common/interfaces/middleware/nest-middleware.interface';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { ApplicationConfig } from '../../application-config';
import { InvalidMiddlewareException } from '../../errors/exceptions/invalid-middleware.exception';
import { RuntimeException } from '../../errors/exceptions/runtime.exception';
@@ -14,6 +13,7 @@ import { MiddlewareBuilder } from '../../middleware/builder';
import { MiddlewareContainer } from '../../middleware/container';
import { MiddlewareModule } from '../../middleware/middleware-module';
import { RouterExceptionFilters } from '../../router/router-exception-filters';
import { NoopHttpAdapter } from '../utils/noop-adapter';
describe('MiddlewareModule', () => {
let middlewareModule: MiddlewareModule;
@@ -43,7 +43,7 @@ describe('MiddlewareModule', () => {
(middlewareModule as any).routerExceptionFilter = new RouterExceptionFilters(
new NestContainer(),
appConfig,
new ExpressAdapter({}),
new NoopHttpAdapter({}),
);
(middlewareModule as any).config = appConfig;
});

View File

@@ -1,12 +1,11 @@
import * as sinon from 'sinon';
import { expect } from 'chai';
import { RouterExceptionFilters } from '../../router/router-exception-filters';
import { UseFilters } from '../../../common/decorators/core/exception-filters.decorator';
import * as sinon from 'sinon';
import { Catch } from '../../../common/decorators/core/catch.decorator';
import { UnknownModuleException } from '../../errors/exceptions/unknown-module.exception';
import { UseFilters } from '../../../common/decorators/core/exception-filters.decorator';
import { ApplicationConfig } from '../../application-config';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { NestContainer } from '../../injector/container';
import { RouterExceptionFilters } from '../../router/router-exception-filters';
import { NoopHttpAdapter } from '../utils/noop-adapter';
describe('RouterExceptionFilters', () => {
let moduleName: string;
@@ -23,7 +22,7 @@ describe('RouterExceptionFilters', () => {
exceptionFilter = new RouterExceptionFilters(
new NestContainer(),
new ApplicationConfig(),
new ExpressAdapter({}),
new NoopHttpAdapter({}),
);
});
describe('create', () => {

View File

@@ -3,7 +3,7 @@ import * as sinon from 'sinon';
import { RouteParamsMetadata } from '../../../common';
import { CUSTOM_ROUTE_AGRS_METADATA } from '../../../common/constants';
import { RouteParamtypes } from '../../../common/enums/route-paramtypes.enum';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { AbstractHttpAdapter } from '../../adapters';
import { ApplicationConfig } from '../../application-config';
import { GuardsConsumer } from '../../guards/guards-consumer';
import { GuardsContextCreator } from '../../guards/guards-context-creator';
@@ -14,6 +14,7 @@ import { PipesConsumer } from '../../pipes/pipes-consumer';
import { PipesContextCreator } from '../../pipes/pipes-context-creator';
import { RouteParamsFactory } from '../../router/route-params-factory';
import { RouterExecutionContext } from '../../router/router-execution-context';
import { NoopHttpAdapter } from '../utils/noop-adapter';
describe('RouterExecutionContext', () => {
let contextCreator: RouterExecutionContext;
@@ -23,6 +24,7 @@ describe('RouterExecutionContext', () => {
let factory: RouteParamsFactory;
let consumer: PipesConsumer;
let guardsConsumer: GuardsConsumer;
let adapter: AbstractHttpAdapter;
beforeEach(() => {
callback = {
@@ -36,6 +38,7 @@ describe('RouterExecutionContext', () => {
consumer = new PipesConsumer();
guardsConsumer = new GuardsConsumer();
adapter = new NoopHttpAdapter({});
contextCreator = new RouterExecutionContext(
factory,
new PipesContextCreator(new NestContainer(), new ApplicationConfig()),
@@ -44,7 +47,7 @@ describe('RouterExecutionContext', () => {
guardsConsumer,
new InterceptorsContextCreator(new NestContainer()),
new InterceptorsConsumer(),
new ExpressAdapter({}),
adapter,
);
});
describe('create', () => {
@@ -259,6 +262,13 @@ describe('RouterExecutionContext', () => {
});
describe('createHandleResponseFn', () => {
describe('when "renderTemplate" is defined', () => {
beforeEach(() => {
sinon
.stub(adapter, 'render')
.callsFake((response, view: string, options: any) => {
return response.render(view, options);
});
});
it('should call "res.render()" with expected args', async () => {
const template = 'template';
const value = 'test';

View File

@@ -1,9 +1,9 @@
import * as sinon from 'sinon';
import { expect } from 'chai';
import { RouterProxy } from '../../router/router-proxy';
import { ExceptionsHandler } from '../../exceptions/exceptions-handler';
import * as sinon from 'sinon';
import { HttpException } from '../../../common/exceptions/http.exception';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { ExceptionsHandler } from '../../exceptions/exceptions-handler';
import { RouterProxy } from '../../router/router-proxy';
import { NoopHttpAdapter } from '../utils/noop-adapter';
describe('RouterProxy', () => {
let routerProxy: RouterProxy;
@@ -11,7 +11,7 @@ describe('RouterProxy', () => {
let handler: ExceptionsHandler;
beforeEach(() => {
handler = new ExceptionsHandler(new ExpressAdapter({}));
handler = new ExceptionsHandler(new NoopHttpAdapter({}));
handlerMock = sinon.mock(handler);
routerProxy = new RouterProxy();
});

View File

@@ -1,16 +1,17 @@
import { isNil, isObject } from '@nestjs/common/utils/shared.utils';
import { expect } from 'chai';
import { of } from 'rxjs';
import * as sinon from 'sinon';
import { RequestMethod } from '../../../common';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { RouterResponseController } from '../../router/router-response-controller';
import { NoopHttpAdapter } from '../utils/noop-adapter';
describe('RouterResponseController', () => {
let adapter: ExpressAdapter;
let adapter: NoopHttpAdapter;
let routerResponseController: RouterResponseController;
beforeEach(() => {
adapter = new ExpressAdapter({});
adapter = new NoopHttpAdapter({});
routerResponseController = new RouterResponseController(adapter);
});
@@ -25,6 +26,17 @@ describe('RouterResponseController', () => {
response.status = sinon.stub().returns(response);
});
describe('when result is', () => {
beforeEach(() => {
sinon
.stub(adapter, 'reply')
.callsFake((responseRef: any, body: any, statusCode: number) => {
const res = responseRef.status(statusCode);
if (isNil(body)) {
return res.send();
}
return isObject(body) ? res.json(body) : res.send(String(body));
});
});
describe('nil', () => {
it('should call send()', async () => {
const value = null;
@@ -102,6 +114,13 @@ describe('RouterResponseController', () => {
});
describe('render', () => {
beforeEach(() => {
sinon
.stub(adapter, 'render')
.callsFake((response, view: string, options: any) => {
return response.render(view, options);
});
});
it('should call "res.render()" with expected args', async () => {
const template = 'template';
const value = 'test';

View File

@@ -3,9 +3,9 @@ import { expect } from 'chai';
import * as sinon from 'sinon';
import { Controller } from '../../../common/decorators/core/controller.decorator';
import { Get } from '../../../common/decorators/http/request-mapping.decorator';
import { ExpressAdapter } from '../../adapters/express-adapter';
import { ApplicationConfig } from '../../application-config';
import { RoutesResolver } from '../../router/routes-resolver';
import { NoopHttpAdapter } from '../utils/noop-adapter';
describe('RoutesResolver', () => {
@Controller('global')
@@ -53,7 +53,7 @@ describe('RoutesResolver', () => {
};
routes.set('TestRoute', routeWrapper);
const appInstance = new ExpressAdapter(router);
const appInstance = new NoopHttpAdapter(router);
const exploreSpy = sinon.spy(
(routesResolver as any).routerBuilder,
'explore',

View File

@@ -0,0 +1,22 @@
import { RequestMethod } from '@nestjs/common';
import { AbstractHttpAdapter } from './../../adapters';
export class NoopHttpAdapter extends AbstractHttpAdapter {
constructor(instance: any) {
super(instance);
}
close(): any {}
initHttpServer(options: any): any {}
useStaticAssets(...args: any[]): any {}
setViewEngine(engine: string): any {}
getRequestMethod(request: any): any {}
getRequestUrl(request: any): any {}
reply(response: any, body: any, statusCode: number): any {}
render(response: any, view: string, options: any): any {}
setErrorHandler(handler: Function): any {}
setNotFoundHandler(handler: Function): any {}
setHeader(response: any, name: string, value: string): any {}
registerParserMiddleware(): any {}
enableCors(options: any): any {}
createMiddlewareFactory(requestMethod: RequestMethod): any {}
}

View File

@@ -40,7 +40,7 @@ export class NestMicroservice extends NestApplicationContext
config: MicroserviceOptions = {},
private readonly applicationConfig: ApplicationConfig,
) {
super(container, [], null);
super(container);
this.registerWsAdapter();
this.microservicesModule.register(container, this.applicationConfig);

View File

@@ -1,9 +1,11 @@
import { RequestMethod } from '@nestjs/common';
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
import { isFunction, isNil, isObject } from '@nestjs/common/utils/shared.utils';
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
import { RouterMethodFactory } from '@nestjs/core/helpers/router-method-factory';
import * as bodyParser from 'body-parser';
import * as cors from 'cors';
import * as express from 'express';
import * as http from 'http';
import * as https from 'https';
@@ -79,6 +81,10 @@ export class ExpressAdapter extends AbstractHttpAdapter {
return request.url;
}
public enableCors(options: CorsOptions) {
this.use(cors(options));
}
public createMiddlewareFactory(
requestMethod: RequestMethod,
): (path: string, callback: Function) => any {
@@ -109,7 +115,7 @@ export class ExpressAdapter extends AbstractHttpAdapter {
.forEach(parserKey => this.use(parserMiddleware[parserKey]));
}
private isMiddlewareApplied(name: string); : boolean; {
private isMiddlewareApplied(name: string): boolean {
const app = this.getInstance();
return (
!!app._router &&

View File

@@ -7,3 +7,4 @@
export * from './adapters';
export * from './interfaces';
export * from './multer';

View File

@@ -1,6 +1,7 @@
import { INestApplication } from '@nestjs/common';
import { ServeStaticOptions } from './serve-static-options.interface';
export interface INestExpressApplication {
export interface INestExpressApplication extends INestApplication {
/**
* A wrapper function around native `express.set()` method.
* Example `app.set('trust proxy', 'loopback')`

View File

@@ -1,15 +1,19 @@
import {
ExecutionContext,
Inject,
mixin,
NestInterceptor,
Optional,
Type,
} from '@nestjs/common';
import * as multer from 'multer';
import { Observable } from 'rxjs';
import { Inject, Optional } from '../../decorators';
import { mixin } from '../../decorators/core/injectable.decorator';
import { ExecutionContext, Type } from '../../interfaces';
import { MULTER_MODULE_OPTIONS } from '../files.constants';
import { MulterModuleOptions } from '../interfaces';
import {
MulterField,
MulterOptions,
} from '../../interfaces/external/multer-options.interface';
import { NestInterceptor } from '../../interfaces/features/nest-interceptor.interface';
import { MULTER_MODULE_OPTIONS } from '../files.constants';
import { MulterModuleOptions } from '../interfaces';
} from '../interfaces/multer-options.interface';
import { transformException } from '../multer/multer.utils';
type MulterInstance = any;
@@ -26,7 +30,7 @@ export function FileFieldsInterceptor(
@Inject(MULTER_MODULE_OPTIONS)
options: MulterModuleOptions = {},
) {
this.multer = multer({
this.multer = (multer as any)({
...options,
...localOptions,
});

View File

@@ -1,12 +1,16 @@
import {
ExecutionContext,
Inject,
mixin,
NestInterceptor,
Optional,
Type,
} from '@nestjs/common';
import * as multer from 'multer';
import { Observable } from 'rxjs';
import { Inject, Optional } from '../../decorators';
import { mixin } from '../../decorators/core/injectable.decorator';
import { ExecutionContext, Type } from '../../interfaces';
import { MulterOptions } from '../../interfaces/external/multer-options.interface';
import { NestInterceptor } from '../../interfaces/features/nest-interceptor.interface';
import { MULTER_MODULE_OPTIONS } from '../files.constants';
import { MulterModuleOptions } from '../interfaces';
import { MulterOptions } from '../interfaces/multer-options.interface';
import { transformException } from '../multer/multer.utils';
type MulterInstance = any;
@@ -23,7 +27,7 @@ export function FileInterceptor(
@Inject(MULTER_MODULE_OPTIONS)
options: MulterModuleOptions = {},
) {
this.multer = multer({
this.multer = (multer as any)({
...options,
...localOptions,
});

View File

@@ -1,12 +1,16 @@
import {
ExecutionContext,
Inject,
mixin,
NestInterceptor,
Optional,
Type,
} from '@nestjs/common';
import * as multer from 'multer';
import { Observable } from 'rxjs';
import { Inject, Optional } from '../../decorators';
import { mixin } from '../../decorators/core/injectable.decorator';
import { ExecutionContext, Type } from '../../interfaces';
import { MulterOptions } from '../../interfaces/external/multer-options.interface';
import { NestInterceptor } from '../../interfaces/features/nest-interceptor.interface';
import { MULTER_MODULE_OPTIONS } from '../files.constants';
import { MulterModuleOptions } from '../interfaces';
import { MulterOptions } from '../interfaces/multer-options.interface';
import { transformException } from '../multer/multer.utils';
type MulterInstance = any;
@@ -24,7 +28,7 @@ export function FilesInterceptor(
@Inject(MULTER_MODULE_OPTIONS)
options: MulterModuleOptions = {},
) {
this.multer = multer({
this.multer = (multer as any)({
...options,
...localOptions,
});

View File

@@ -1,5 +1,6 @@
import { ModuleMetadata, Type } from '../../interfaces';
import { MulterOptions } from '../../interfaces/external/multer-options.interface';
import { Type } from '@nestjs/common';
import { ModuleMetadata } from '@nestjs/common/interfaces';
import { MulterOptions } from '../interfaces/multer-options.interface';
export interface MulterModuleOptions extends MulterOptions {}

View File

@@ -1,5 +1,4 @@
import { Module } from './../decorators';
import { DynamicModule, Provider } from './../interfaces';
import { DynamicModule, Module, Provider } from '@nestjs/common';
import { MULTER_MODULE_OPTIONS } from './files.constants';
import {
MulterModuleAsyncOptions,

View File

@@ -1,4 +1,8 @@
import { BadRequestException, HttpException, PayloadTooLargeException } from '../../exceptions';
import {
BadRequestException,
HttpException,
PayloadTooLargeException,
} from '@nestjs/common';
import { multerExceptions } from './multer.constants';
export function transformException(error: Error | undefined) {

View File

@@ -12,7 +12,9 @@
"dependencies": {
"@types/express": "^4.0.39",
"body-parser": "1.18.3",
"express": "4.16.3"
"cors": "2.8.4",
"express": "4.16.3",
"multer": "1.3.0"
},
"peerDependencies": {}
}

View File

@@ -2,7 +2,7 @@ import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.hos
import { expect } from 'chai';
import { of } from 'rxjs';
import * as sinon from 'sinon';
import { FileFieldsInterceptor } from '../../../files/interceptors/file-fields.interceptor';
import { FileFieldsInterceptor } from '../../../multer/interceptors/file-fields.interceptor';
describe('FileFieldsInterceptor', () => {
it('should return metatype with expected structure', async () => {

View File

@@ -2,7 +2,7 @@ import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.hos
import { expect } from 'chai';
import { of } from 'rxjs';
import * as sinon from 'sinon';
import { FileInterceptor } from '../../../files/interceptors/file.interceptor';
import { FileInterceptor } from '../../../multer/interceptors/file.interceptor';
describe('FileInterceptor', () => {
it('should return metatype with expected structure', async () => {

View File

@@ -2,7 +2,7 @@ import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.hos
import { expect } from 'chai';
import { of } from 'rxjs';
import * as sinon from 'sinon';
import { FilesInterceptor } from '../../../files/interceptors/files.interceptor';
import { FilesInterceptor } from '../../../multer/interceptors/files.interceptor';
describe('FilesInterceptor', () => {
it('should return metatype with expected structure', async () => {

View File

@@ -1,8 +1,7 @@
import { expect } from 'chai';
import { MULTER_MODULE_OPTIONS } from '../../../files/files.constants';
import { MulterModule } from '../../../files/multer.module';
import { Provider, FactoryProvider } from '../../../interfaces';
import * as sinon from 'sinon';
import { MULTER_MODULE_OPTIONS } from '../../../multer/files.constants';
import { MulterModule } from '../../../multer/multer.module';
describe('MulterModule', () => {
describe('register', () => {

View File

@@ -1,11 +1,11 @@
import { expect } from 'chai';
import {
BadRequestException,
HttpException,
PayloadTooLargeException,
} from '../../../exceptions';
import { multerExceptions } from '../../../files/multer/multer.constants';
import { transformException } from '../../../files/multer/multer.utils';
} from '@nestjs/common';
import { expect } from 'chai';
import { multerExceptions } from '../../../multer/multer/multer.constants';
import { transformException } from '../../../multer/multer/multer.utils';
describe('transformException', () => {
describe('if error does not exist', () => {

View File

@@ -1,109 +1,114 @@
import { RequestMethod } from '@nestjs/common';
import { ErrorHandler, RequestHandler } from '@nestjs/common/interfaces';
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
import * as fastify from 'fastify';
import * as cors from 'fastify-cors';
import * as formBody from 'fastify-formbody';
import * as pathToRegexp from 'path-to-regexp';
export class FastifyAdapter extends AbstractHttpAdapter {
setBaseViewsDir(path: string) {}
registerParserMiddleware() {
this.register(loadPackage('fastify-formbody', 'FastifyAdapter'));
}
constructor(options?: any) {
super(loadPackage('fastify', 'FastifyAdapter')(options));
constructor(options?: fastify.ServerOptions) {
super(fastify(options));
}
use(handler: RequestHandler | ErrorHandler);
use(path: any, handler: RequestHandler | ErrorHandler);
use(...args: any[]) {
public use(handler: RequestHandler | ErrorHandler);
public use(path: any, handler: RequestHandler | ErrorHandler);
public use(...args: any[]) {
return this.instance.use(...args);
}
get(handler: RequestHandler);
get(path: any, handler: RequestHandler);
get(...args: any[]) {
public get(handler: RequestHandler);
public get(path: any, handler: RequestHandler);
public get(...args: any[]) {
return this.instance.get(...args);
}
post(handler: RequestHandler);
post(path: any, handler: RequestHandler);
post(...args: any[]) {
public post(handler: RequestHandler);
public post(path: any, handler: RequestHandler);
public post(...args: any[]) {
return this.instance.post(...args);
}
head(handler: RequestHandler);
head(path: any, handler: RequestHandler);
head(...args: any[]) {
public head(handler: RequestHandler);
public head(path: any, handler: RequestHandler);
public head(...args: any[]) {
return this.instance.head(...args);
}
delete(handler: RequestHandler);
delete(path: any, handler: RequestHandler);
delete(...args: any[]) {
public delete(handler: RequestHandler);
public delete(path: any, handler: RequestHandler);
public delete(...args: any[]) {
return this.instance.delete(...args);
}
put(handler: RequestHandler);
put(path: any, handler: RequestHandler);
put(...args: any[]) {
public put(handler: RequestHandler);
public put(path: any, handler: RequestHandler);
public put(...args: any[]) {
return this.instance.put(...args);
}
patch(handler: RequestHandler);
patch(path: any, handler: RequestHandler);
patch(...args: any[]) {
public patch(handler: RequestHandler);
public patch(path: any, handler: RequestHandler);
public patch(...args: any[]) {
return this.instance.patch(...args);
}
options(handler: RequestHandler);
options(path: any, handler: RequestHandler);
options(...args: any[]) {
public options(handler: RequestHandler);
public options(path: any, handler: RequestHandler);
public options(...args: any[]) {
return this.instance.options(...args);
}
listen(port: string | number, callback?: () => void);
listen(port: string | number, hostname: string, callback?: () => void);
listen(port: any, hostname?: any, callback?: any) {
public listen(port: string | number, callback?: () => void);
public listen(port: string | number, hostname: string, callback?: () => void);
public listen(port: any, hostname?: any, callback?: any) {
return this.instance.listen(port, hostname, callback);
}
reply(response, body: any, statusCode: number) {
public reply(response, body: any, statusCode: number) {
return response.code(statusCode).send(body);
}
render(response, view: string, options: any) {
public render(response, view: string, options: any) {
return response.view(view, options);
}
setErrorHandler(handler: Function) {
public setErrorHandler(handler: Function) {
return this.instance.setErrorHandler(handler);
}
setNotFoundHandler(handler: Function) {
public setNotFoundHandler(handler: Function) {
return this.instance.setNotFoundHandler(handler);
}
getHttpServer<T = any>(): T {
public getHttpServer<T = any>(): T {
return this.instance.server as T;
}
getInstance<T = any>(): T {
public getInstance<T = any>(): T {
return this.instance as T;
}
register(...args: any[]) {
public register(...args: any[]) {
return this.instance.register(...args);
}
inject(...args: any[]) {
public inject(...args: any[]) {
return this.instance.inject(...args);
}
close() {
public close() {
return this.instance.close();
}
useStaticAssets(options: {
public initHttpServer(options: NestApplicationOptions) {
this.httpServer = this.instance.server;
}
public useStaticAssets(options: {
root: string;
prefix?: string;
setHeaders?: Function;
@@ -122,19 +127,27 @@ export class FastifyAdapter extends AbstractHttpAdapter {
);
}
setHeader(response, name: string, value: string) {
public setHeader(response, name: string, value: string) {
return response.header(name, value);
}
getRequestMethod(request): string {
public getRequestMethod(request): string {
return request.raw.method;
}
getRequestUrl(request): string {
public getRequestUrl(request): string {
return request.raw.url;
}
createMiddlewareFactory(
public enableCors(options: CorsOptions) {
this.register(cors(options));
}
public registerParserMiddleware() {
this.register(formBody);
}
public createMiddlewareFactory(
requestMethod: RequestMethod,
): (path: string, callback: Function) => any {
return (path: string, callback: Function) => {

View File

@@ -1 +1 @@
export * from './nest-express-application.interface';
export * from './nest-fastify-application.interface';

View File

@@ -1,4 +1,7 @@
export interface INestFastifyApplication {
import { INestApplication } from '@nestjs/common';
import { HTTPInjectOptions, HTTPInjectResponse } from 'fastify';
export interface INestFastifyApplication extends INestApplication {
/**
* A wrapper function around native `fastify.register()` method.
* Example `app.register(require('fastify-formbody'))`
@@ -33,45 +36,3 @@ export interface INestFastifyApplication {
*/
inject(opts: HTTPInjectOptions | string): Promise<HTTPInjectResponse>;
}
/** Reference: https://github.com/fastify/fastify */
export type HTTPMethod =
| 'DELETE'
| 'GET'
| 'HEAD'
| 'PATCH'
| 'POST'
| 'PUT'
| 'OPTIONS';
/**
* Fake http inject options
*/
export interface HTTPInjectOptions {
url: string;
method?: HTTPMethod;
authority?: string;
headers?: object;
remoteAddress?: string;
payload?: string | object | Buffer | any;
simulate?: {
end?: boolean;
split?: boolean;
error?: boolean;
close?: boolean;
};
validate?: boolean;
}
/**
* Fake http inject response
*/
export interface HTTPInjectResponse {
raw: any;
headers: object;
statusCode: number;
statusMessage: string;
payload: string;
rawPayload: Buffer;
trailers: object;
}

View File

@@ -10,9 +10,10 @@
"url": "https://github.com/nestjs/nest"
},
"dependencies": {
"@types/express": "^4.0.39",
"body-parser": "1.18.3",
"express": "4.16.3"
"fastify": "^1.13.1",
"fastify-cors": "^0.2.0",
"fastify-formbody": "2.0.3",
"path-to-regexp": "2.2.1"
},
"peerDependencies": {}
}