refactor(core): Convert dynamic node-parameter routes to a decorated controller (no-changelog) (#7284)

1. Reduce a lot of code duplication
2. Move more endpoints out of `Server.ts`
3. Move all query-param parsing and validation into a middleware to make
the route handlers simpler.
This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2023-11-17 12:03:05 +01:00
committed by GitHub
parent 05ed86c64b
commit fc60e9a809
14 changed files with 426 additions and 572 deletions

View File

@@ -0,0 +1,120 @@
import { Service } from 'typedi';
import type { RequestHandler } from 'express';
import { NextFunction, Response } from 'express';
import type {
INodeListSearchResult,
INodePropertyOptions,
ResourceMapperFields,
} from 'n8n-workflow';
import { jsonParse } from 'n8n-workflow';
import { Authorized, Get, Middleware, RestController } from '@/decorators';
import { getBase } from '@/WorkflowExecuteAdditionalData';
import { DynamicNodeParametersService } from '@/services/dynamicNodeParameters.service';
import { DynamicNodeParametersRequest } from '@/requests';
import { BadRequestError } from '@/ResponseHelper';
const assertMethodName: RequestHandler = (req, res, next) => {
const { methodName } = req.query as DynamicNodeParametersRequest.BaseRequest['query'];
if (!methodName) {
throw new BadRequestError('Parameter methodName is required.');
}
next();
};
@Service()
@Authorized()
@RestController('/dynamic-node-parameters')
export class DynamicNodeParametersController {
constructor(private readonly service: DynamicNodeParametersService) {}
@Middleware()
parseQueryParams(
req: DynamicNodeParametersRequest.BaseRequest,
res: Response,
next: NextFunction,
) {
const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.query;
if (!nodeTypeAndVersion) {
throw new BadRequestError('Parameter nodeTypeAndVersion is required.');
}
if (!currentNodeParameters) {
throw new BadRequestError('Parameter currentNodeParameters is required.');
}
req.params = {
nodeTypeAndVersion: jsonParse(nodeTypeAndVersion),
currentNodeParameters: jsonParse(currentNodeParameters),
credentials: credentials ? jsonParse(credentials) : undefined,
};
next();
}
/** Returns parameter values which normally get loaded from an external API or get generated dynamically */
@Get('/options')
async getOptions(req: DynamicNodeParametersRequest.Options): Promise<INodePropertyOptions[]> {
const { path, methodName, loadOptions } = req.query;
const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.params;
const additionalData = await getBase(req.user.id, currentNodeParameters);
if (methodName) {
return this.service.getOptionsViaMethodName(
methodName,
path,
additionalData,
nodeTypeAndVersion,
currentNodeParameters,
credentials,
);
}
if (loadOptions) {
return this.service.getOptionsViaLoadOptions(
jsonParse(loadOptions),
additionalData,
nodeTypeAndVersion,
currentNodeParameters,
credentials,
);
}
return [];
}
@Get('/resource-locator-results', { middlewares: [assertMethodName] })
async getResourceLocatorResults(
req: DynamicNodeParametersRequest.ResourceLocatorResults,
): Promise<INodeListSearchResult | undefined> {
const { path, methodName, filter, paginationToken } = req.query;
const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.params;
const additionalData = await getBase(req.user.id, currentNodeParameters);
return this.service.getResourceLocatorResults(
methodName,
path,
additionalData,
nodeTypeAndVersion,
currentNodeParameters,
credentials,
filter,
paginationToken,
);
}
@Get('/resource-mapper-fields', { middlewares: [assertMethodName] })
async getResourceMappingFields(
req: DynamicNodeParametersRequest.ResourceMapperFields,
): Promise<ResourceMapperFields | undefined> {
const { path, methodName } = req.query;
const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.params;
const additionalData = await getBase(req.user.id, currentNodeParameters);
return this.service.getResourceMappingFields(
methodName,
path,
additionalData,
nodeTypeAndVersion,
currentNodeParameters,
credentials,
);
}
}