mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feat(@nestjs/core) integration custom decorators with pipes
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
# 4.4.0 @soon
|
||||
## 4.4.1
|
||||
- **common**: `ValidationPipe` improvement
|
||||
- **common**: custom route params decorators accepts pipes now
|
||||
- **core**: bugfix #268
|
||||
|
||||
## 4.4.0
|
||||
- **core**: possibility to create the `NestApplicationContext` using `NestFactory.createApplicationContext()` (Nest application without HTTP server / microservice in the background)
|
||||
- **core**: create custom params decorators feature (`createRouteParamDecorator()`)
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
export declare type Paramtype = 'body' | 'query' | 'param';
|
||||
export declare type Paramtype = 'body' | 'query' | 'param' | 'custom';
|
||||
|
||||
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const class_validator_1 = require("class-validator");
|
||||
const class_transformer_1 = require("class-transformer");
|
||||
const index_1 = require("../index");
|
||||
const shared_utils_1 = require("../utils/shared.utils");
|
||||
let ValidationPipe = class ValidationPipe {
|
||||
transform(value, metadata) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
@@ -34,7 +35,7 @@ let ValidationPipe = class ValidationPipe {
|
||||
}
|
||||
toValidate(metatype) {
|
||||
const types = [String, Boolean, Number, Array, Object];
|
||||
return !types.find(type => metatype === type);
|
||||
return !types.find(type => metatype === type) && !shared_utils_1.isNil(metatype);
|
||||
}
|
||||
};
|
||||
ValidationPipe = __decorate([
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CustomParamFactory } from '../../interfaces/custom-route-param-factory.interface';
|
||||
import { ParamData } from './route-params.decorator';
|
||||
import { PipeTransform } from '../../index';
|
||||
/**
|
||||
* Create route params custom decorator
|
||||
* @param factory
|
||||
*/
|
||||
export declare const createRouteParamDecorator: (factory: CustomParamFactory) => (data?: ParamData) => ParameterDecorator;
|
||||
export declare function createRouteParamDecorator(factory: CustomParamFactory): (data?: any, ...pipes: PipeTransform<any>[]) => ParameterDecorator;
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const constants_1 = require("../../constants");
|
||||
const assignCustomMetadata = (args, paramtype, index, factory, data) => (Object.assign({}, args, { [`${index}:${paramtype}${constants_1.CUSTOM_ROUTE_AGRS_METADATA}:${index}`]: {
|
||||
const assignCustomMetadata = (args, paramtype, index, factory, data, ...pipes) => (Object.assign({}, args, { [`${paramtype}${constants_1.CUSTOM_ROUTE_AGRS_METADATA}:${index}`]: {
|
||||
index,
|
||||
factory,
|
||||
data,
|
||||
pipes,
|
||||
} }));
|
||||
const randomString = () => Math.random().toString(36).substring(2, 15);
|
||||
const randomString = () => Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15);
|
||||
/**
|
||||
* Create route params custom decorator
|
||||
* @param factory
|
||||
*/
|
||||
exports.createRouteParamDecorator = (factory) => {
|
||||
function createRouteParamDecorator(factory) {
|
||||
const paramtype = randomString() + randomString();
|
||||
return (data) => (target, key, index) => {
|
||||
return (data, ...pipes) => (target, key, index) => {
|
||||
const args = Reflect.getMetadata(constants_1.ROUTE_ARGS_METADATA, target, key) || {};
|
||||
Reflect.defineMetadata(constants_1.ROUTE_ARGS_METADATA, assignCustomMetadata(args, paramtype, index, factory, data), target, key);
|
||||
Reflect.defineMetadata(constants_1.ROUTE_ARGS_METADATA, assignCustomMetadata(args, paramtype, index, factory, data, ...pipes), target, key);
|
||||
};
|
||||
};
|
||||
}
|
||||
exports.createRouteParamDecorator = createRouteParamDecorator;
|
||||
|
||||
@@ -7,7 +7,7 @@ class ParamsTokenFactory {
|
||||
case route_paramtypes_enum_1.RouteParamtypes.BODY: return 'body';
|
||||
case route_paramtypes_enum_1.RouteParamtypes.PARAM: return 'param';
|
||||
case route_paramtypes_enum_1.RouteParamtypes.QUERY: return 'query';
|
||||
default: return null;
|
||||
default: return 'custom';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
|
||||
export interface IRouteParamsFactory {
|
||||
exchangeKeyForValue(key: RouteParamtypes, data: any, {req, res, next}: {
|
||||
exchangeKeyForValue(key: RouteParamtypes | string, data: any, {req, res, next}: {
|
||||
req: any;
|
||||
res: any;
|
||||
next: any;
|
||||
|
||||
2
lib/core/router/route-params-factory.d.ts
vendored
2
lib/core/router/route-params-factory.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
|
||||
import { IRouteParamsFactory } from './interfaces/route-params-factory.interface';
|
||||
export declare class RouteParamsFactory implements IRouteParamsFactory {
|
||||
exchangeKeyForValue(key: RouteParamtypes, data: any, {req, res, next}: {
|
||||
exchangeKeyForValue(key: RouteParamtypes | string, data: any, {req, res, next}: {
|
||||
req: any;
|
||||
res: any;
|
||||
next: any;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { InterceptorsContextCreator } from '../interceptors/interceptors-context
|
||||
import { InterceptorsConsumer } from '../interceptors/interceptors-consumer';
|
||||
export interface ParamProperties {
|
||||
index: number;
|
||||
type: RouteParamtypes;
|
||||
type: RouteParamtypes | string;
|
||||
data: ParamData;
|
||||
pipes: PipeTransform<any>[];
|
||||
extractValue: (req, res, next) => any;
|
||||
@@ -28,7 +28,7 @@ export declare class RouterExecutionContext {
|
||||
private readonly responseController;
|
||||
constructor(paramsFactory: IRouteParamsFactory, pipesContextCreator: PipesContextCreator, pipesConsumer: PipesConsumer, guardsContextCreator: GuardsContextCreator, guardsConsumer: GuardsConsumer, interceptorsContextCreator: InterceptorsContextCreator, interceptorsConsumer: InterceptorsConsumer);
|
||||
create(instance: Controller, callback: (...args) => any, methodName: string, module: string, requestMethod: RequestMethod): (req: any, res: any, next: any) => Promise<any>;
|
||||
mapParamType(key: string): RouteParamtypes | number;
|
||||
mapParamType(key: string): string;
|
||||
reflectCallbackMetadata(instance: Controller, methodName: string): RouteParamsMetadata;
|
||||
reflectCallbackParamtypes(instance: Controller, methodName: string): any[];
|
||||
reflectHttpStatusCode(callback: (...args) => any): number;
|
||||
|
||||
@@ -58,7 +58,7 @@ class RouterExecutionContext {
|
||||
}
|
||||
mapParamType(key) {
|
||||
const keyPair = key.split(':');
|
||||
return Number(keyPair[0]);
|
||||
return keyPair[0];
|
||||
}
|
||||
reflectCallbackMetadata(instance, methodName) {
|
||||
return Reflect.getMetadata(constants_1.ROUTE_ARGS_METADATA, instance, methodName);
|
||||
@@ -84,8 +84,9 @@ class RouterExecutionContext {
|
||||
const customExtractValue = this.getCustomFactory(factory, data);
|
||||
return { index, extractValue: customExtractValue, type, data, pipes };
|
||||
}
|
||||
const extractValue = (req, res, next) => this.paramsFactory.exchangeKeyForValue(type, data, { req, res, next });
|
||||
return { index, extractValue, type, data, pipes };
|
||||
const nType = Number(type);
|
||||
const extractValue = (req, res, next) => this.paramsFactory.exchangeKeyForValue(nType, data, { req, res, next });
|
||||
return { index, extractValue, type: nType, data, pipes };
|
||||
});
|
||||
}
|
||||
getCustomFactory(factory, data) {
|
||||
@@ -103,7 +104,8 @@ class RouterExecutionContext {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (type === route_paramtypes_enum_1.RouteParamtypes.BODY
|
||||
|| type === route_paramtypes_enum_1.RouteParamtypes.QUERY
|
||||
|| type === route_paramtypes_enum_1.RouteParamtypes.PARAM) {
|
||||
|| type === route_paramtypes_enum_1.RouteParamtypes.PARAM
|
||||
|| shared_utils_1.isString(type)) {
|
||||
return yield this.pipesConsumer.apply(value, { metatype, type, data }, transforms);
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nestjs",
|
||||
"version": "4.4.0",
|
||||
"version": "4.4.1",
|
||||
"description": "Modern, fast, powerful node.js web framework",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export type Paramtype = 'body' | 'query' | 'param';
|
||||
export type Paramtype = 'body' | 'query' | 'param' | 'custom';
|
||||
@@ -2,6 +2,7 @@ import { validate } from 'class-validator';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { PipeTransform } from '../interfaces/pipe-transform.interface';
|
||||
import { Pipe, ArgumentMetadata, BadRequestException } from '../index';
|
||||
import { isNil } from '../utils/shared.utils';
|
||||
|
||||
@Pipe()
|
||||
export class ValidationPipe implements PipeTransform<any> {
|
||||
@@ -20,6 +21,6 @@ export class ValidationPipe implements PipeTransform<any> {
|
||||
|
||||
private toValidate(metatype): boolean {
|
||||
const types = [String, Boolean, Number, Array, Object];
|
||||
return !types.find(type => metatype === type);
|
||||
return !types.find(type => metatype === type) && !isNil(metatype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,63 @@
|
||||
import { ROUTE_ARGS_METADATA, CUSTOM_ROUTE_AGRS_METADATA } from '../../constants';
|
||||
import {
|
||||
ROUTE_ARGS_METADATA,
|
||||
CUSTOM_ROUTE_AGRS_METADATA,
|
||||
} from '../../constants';
|
||||
import { CustomParamFactory } from '../../interfaces/custom-route-param-factory.interface';
|
||||
import { RouteParamsMetadata, ParamData } from './route-params.decorator';
|
||||
import { PipeTransform } from '../../index';
|
||||
import { isNil, isString } from '../shared.utils';
|
||||
|
||||
const assignCustomMetadata = (
|
||||
args: RouteParamsMetadata,
|
||||
paramtype: number|string,
|
||||
index: number,
|
||||
factory: CustomParamFactory,
|
||||
data?: ParamData,
|
||||
args: RouteParamsMetadata,
|
||||
paramtype: number | string,
|
||||
index: number,
|
||||
factory: CustomParamFactory,
|
||||
data?: ParamData,
|
||||
...pipes: PipeTransform<any>[]
|
||||
) => ({
|
||||
...args,
|
||||
[`${index}:${paramtype}${CUSTOM_ROUTE_AGRS_METADATA}:${index}`]: {
|
||||
index,
|
||||
factory,
|
||||
data,
|
||||
},
|
||||
...args,
|
||||
[`${paramtype}${CUSTOM_ROUTE_AGRS_METADATA}:${index}`]: {
|
||||
index,
|
||||
factory,
|
||||
data,
|
||||
pipes,
|
||||
},
|
||||
});
|
||||
|
||||
const randomString = () => Math.random().toString(36).substring(2, 15);
|
||||
const randomString = () =>
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15);
|
||||
|
||||
/**
|
||||
* Create route params custom decorator
|
||||
* @param factory
|
||||
* @param factory
|
||||
*/
|
||||
export const createRouteParamDecorator = (factory: CustomParamFactory) => {
|
||||
const paramtype = randomString() + randomString();
|
||||
return (data?: ParamData): ParameterDecorator => (target, key, index) => {
|
||||
const args = Reflect.getMetadata(ROUTE_ARGS_METADATA, target, key) || {};
|
||||
Reflect.defineMetadata(
|
||||
ROUTE_ARGS_METADATA,
|
||||
assignCustomMetadata(args, paramtype, index, factory, data),
|
||||
target,
|
||||
key,
|
||||
);
|
||||
};
|
||||
};
|
||||
export function createRouteParamDecorator(
|
||||
factory: CustomParamFactory,
|
||||
): (
|
||||
data?: any,
|
||||
...pipes: PipeTransform<any>[],
|
||||
) => ParameterDecorator {
|
||||
const paramtype = randomString() + randomString();
|
||||
return (data?, ...pipes: PipeTransform<any>[]): ParameterDecorator => (
|
||||
target,
|
||||
key,
|
||||
index,
|
||||
) => {
|
||||
const args = Reflect.getMetadata(ROUTE_ARGS_METADATA, target, key) || {};
|
||||
Reflect.defineMetadata(
|
||||
ROUTE_ARGS_METADATA,
|
||||
assignCustomMetadata(
|
||||
args,
|
||||
paramtype,
|
||||
index,
|
||||
factory,
|
||||
data,
|
||||
...pipes,
|
||||
),
|
||||
target,
|
||||
key,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const assignMetadata = (
|
||||
paramtype: RouteParamtypes,
|
||||
index: number,
|
||||
data?: ParamData,
|
||||
...pipes: PipeTransform<any>[]
|
||||
...pipes: PipeTransform<any>[],
|
||||
) => ({
|
||||
...args,
|
||||
[`${paramtype}:${index}`]: {
|
||||
@@ -41,7 +41,7 @@ const createRouteParamDecorator = (paramtype: RouteParamtypes) => {
|
||||
|
||||
const createPipesRouteParamDecorator = (paramtype: RouteParamtypes) => (
|
||||
data?,
|
||||
...pipes: PipeTransform<any>[]
|
||||
...pipes: PipeTransform<any>[],
|
||||
): ParameterDecorator => (target, key, index) => {
|
||||
const args = Reflect.getMetadata(ROUTE_ARGS_METADATA, target, key) || {};
|
||||
const hasParamData = isNil(data) || isString(data);
|
||||
|
||||
@@ -7,7 +7,7 @@ export class ParamsTokenFactory {
|
||||
case RouteParamtypes.BODY: return 'body';
|
||||
case RouteParamtypes.PARAM: return 'param';
|
||||
case RouteParamtypes.QUERY: return 'query';
|
||||
default: return null;
|
||||
default: return 'custom';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
|
||||
|
||||
export interface IRouteParamsFactory {
|
||||
exchangeKeyForValue(key: RouteParamtypes, data, { req, res, next });
|
||||
exchangeKeyForValue(key: RouteParamtypes | string, data, { req, res, next });
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
|
||||
import { IRouteParamsFactory } from './interfaces/route-params-factory.interface';
|
||||
|
||||
export class RouteParamsFactory implements IRouteParamsFactory {
|
||||
public exchangeKeyForValue(key: RouteParamtypes, data, { req, res, next }) {
|
||||
public exchangeKeyForValue(key: RouteParamtypes | string, data, { req, res, next }) {
|
||||
switch (key) {
|
||||
case RouteParamtypes.NEXT: return next;
|
||||
case RouteParamtypes.REQUEST: return req;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'reflect-metadata';
|
||||
import { ROUTE_ARGS_METADATA, PARAMTYPES_METADATA, HTTP_CODE_METADATA, CUSTOM_ROUTE_AGRS_METADATA } from '@nestjs/common/constants';
|
||||
import { isUndefined, isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import { isUndefined, isFunction, isString } from '@nestjs/common/utils/shared.utils';
|
||||
import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
|
||||
import { Controller, Transform } from '@nestjs/common/interfaces';
|
||||
import { RouteParamsMetadata } from '@nestjs/common/utils';
|
||||
@@ -17,7 +17,7 @@ import { InterceptorsConsumer } from '../interceptors/interceptors-consumer';
|
||||
|
||||
export interface ParamProperties {
|
||||
index: number;
|
||||
type: RouteParamtypes;
|
||||
type: RouteParamtypes | string;
|
||||
data: ParamData;
|
||||
pipes: PipeTransform<any>[];
|
||||
extractValue: (req, res, next) => any;
|
||||
@@ -73,9 +73,9 @@ export class RouterExecutionContext {
|
||||
};
|
||||
}
|
||||
|
||||
public mapParamType(key: string): RouteParamtypes | number {
|
||||
public mapParamType(key: string): string {
|
||||
const keyPair = key.split(':');
|
||||
return Number(keyPair[0]);
|
||||
return keyPair[0];
|
||||
}
|
||||
|
||||
public reflectCallbackMetadata(instance: Controller, methodName: string): RouteParamsMetadata {
|
||||
@@ -108,8 +108,9 @@ export class RouterExecutionContext {
|
||||
const customExtractValue = this.getCustomFactory(factory, data);
|
||||
return { index, extractValue: customExtractValue, type, data, pipes };
|
||||
}
|
||||
const extractValue = (req, res, next) => this.paramsFactory.exchangeKeyForValue(type, data, { req, res, next });
|
||||
return { index, extractValue, type, data, pipes };
|
||||
const nType = Number(type);
|
||||
const extractValue = (req, res, next) => this.paramsFactory.exchangeKeyForValue(nType, data, { req, res, next });
|
||||
return { index, extractValue, type: nType, data, pipes };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -136,7 +137,8 @@ export class RouterExecutionContext {
|
||||
|
||||
if (type === RouteParamtypes.BODY
|
||||
|| type === RouteParamtypes.QUERY
|
||||
|| type === RouteParamtypes.PARAM) {
|
||||
|| type === RouteParamtypes.PARAM
|
||||
|| isString(type)) {
|
||||
|
||||
return await this.pipesConsumer.apply(value, { metatype, type, data }, transforms);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ describe('ParamsTokenFactory', () => {
|
||||
});
|
||||
});
|
||||
describe('not available', () => {
|
||||
it('should returns null', () => {
|
||||
expect(factory.exchangeEnumForString(-1)).to.be.eql(null);
|
||||
it('should returns "custom"', () => {
|
||||
expect(factory.exchangeEnumForString(-1)).to.be.eql('custom');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user