Skip to content

Commit

Permalink
feat(common,core): make HttpServer#applyVersionFilter mandatory
Browse files Browse the repository at this point in the history
  • Loading branch information
micalevisk committed May 17, 2022
1 parent 79cccd0 commit 0356397
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 879 deletions.
8 changes: 2 additions & 6 deletions packages/common/interfaces/http/http-server.interface.ts
Expand Up @@ -74,13 +74,9 @@ export interface HttpServer<TRequest = any, TResponse = any> {
close(): any;
getType(): string;
init?(): Promise<void>;
applyVersionFilter?(
applyVersionFilter(
handler: Function,
version: VersionValue,
versioningOptions: VersioningOptions,
): <TRequest extends Record<string, any> = any, TResponse = any>(
req: TRequest,
res: TResponse,
next: () => void,
) => any;
): (req: TRequest, res: TResponse, next: () => void) => Function;
}
9 changes: 7 additions & 2 deletions packages/core/adapters/http-adapter.ts
@@ -1,5 +1,5 @@
import { HttpServer, RequestMethod } from '@nestjs/common';
import { RequestHandler } from '@nestjs/common/interfaces';
import { HttpServer, RequestMethod, VersioningOptions } from '@nestjs/common';
import { RequestHandler, VersionValue } from '@nestjs/common/interfaces';
import {
CorsOptions,
CorsOptionsDelegate,
Expand Down Expand Up @@ -121,4 +121,9 @@ export abstract class AbstractHttpAdapter<
| ((path: string, callback: Function) => any)
| Promise<(path: string, callback: Function) => any>;
abstract getType(): string;
abstract applyVersionFilter(
handler: Function,
version: VersionValue,
versioningOptions: VersioningOptions,
): (req: TRequest, res: TResponse, next: () => void) => Function;
}
127 changes: 1 addition & 126 deletions packages/core/router/router-explorer.ts
Expand Up @@ -334,132 +334,7 @@ export class RouterExplorer {
) {
const { versioningOptions } = routePathMetadata;
const version = this.routePathFactory.getVersion(routePathMetadata);
if (router?.applyVersionFilter) {
return router.applyVersionFilter(handler, version, versioningOptions);
}
/**
* TODO(v9): This was left for backward-compatibility and can be removed.
*/
return <TRequest extends Record<string, any> = any, TResponse = any>(
req: TRequest,
res: TResponse,
next: () => void,
) => {
if (version === VERSION_NEUTRAL) {
return handler(req, res, next);
}
// URL Versioning is done via the path, so the filter continues forward
if (versioningOptions.type === VersioningType.URI) {
return handler(req, res, next);
}

// Custom Extractor Versioning Handler
if (versioningOptions.type === VersioningType.CUSTOM) {
const extractedVersion = versioningOptions.extractor(req) as
| string
| string[]
| Array<string | symbol>;

if (Array.isArray(version)) {
if (
Array.isArray(extractedVersion) &&
version.filter(
extractedVersion.includes as (
value: string | symbol,
index: number,
array: Array<string | symbol>,
) => boolean,
).length
) {
return handler(req, res, next);
} else if (
isString(extractedVersion) &&
version.includes(extractedVersion)
) {
return handler(req, res, next);
}
} else {
if (
Array.isArray(extractedVersion) &&
extractedVersion.includes(version)
) {
return handler(req, res, next);
} else if (
isString(extractedVersion) &&
version === extractedVersion
) {
return handler(req, res, next);
}
}
}

// Media Type (Accept Header) Versioning Handler
if (versioningOptions.type === VersioningType.MEDIA_TYPE) {
const MEDIA_TYPE_HEADER = 'Accept';
const acceptHeaderValue: string | undefined =
req.headers?.[MEDIA_TYPE_HEADER] ||
req.headers?.[MEDIA_TYPE_HEADER.toLowerCase()];

const acceptHeaderVersionParameter = acceptHeaderValue
? acceptHeaderValue.split(';')[1]
: undefined;

// No version was supplied
if (isUndefined(acceptHeaderVersionParameter)) {
if (Array.isArray(version)) {
if (version.includes(VERSION_NEUTRAL)) {
return handler(req, res, next);
}
}
} else {
const headerVersion = acceptHeaderVersionParameter.split(
versioningOptions.key,
)[1];

if (Array.isArray(version)) {
if (version.includes(headerVersion)) {
return handler(req, res, next);
}
} else if (isString(version)) {
if (version === headerVersion) {
return handler(req, res, next);
}
}
}
}
// Header Versioning Handler
else if (versioningOptions.type === VersioningType.HEADER) {
const customHeaderVersionParameter: string | undefined =
req.headers?.[versioningOptions.header] ||
req.headers?.[versioningOptions.header.toLowerCase()];

// No version was supplied
if (isUndefined(customHeaderVersionParameter)) {
if (Array.isArray(version)) {
if (version.includes(VERSION_NEUTRAL)) {
return handler(req, res, next);
}
}
} else {
if (Array.isArray(version)) {
if (version.includes(customHeaderVersionParameter)) {
return handler(req, res, next);
}
} else if (isString(version)) {
if (version === customHeaderVersionParameter) {
return handler(req, res, next);
}
}
}
}

if (!next) {
throw new InternalServerErrorException(
'HTTP adapter does not support filtering on version',
);
}
return next();
};
return router.applyVersionFilter(handler, version, versioningOptions);
}

private createCallbackProxy(
Expand Down

0 comments on commit 0356397

Please sign in to comment.