Skip to content

Commit

Permalink
refactor(core): Refactor node-details endpoints (no-changelog)
Browse files Browse the repository at this point in the history
  • Loading branch information
netroy committed Oct 25, 2023
1 parent 742c8a8 commit 81ac215
Show file tree
Hide file tree
Showing 14 changed files with 427 additions and 582 deletions.
191 changes: 4 additions & 187 deletions packages/cli/src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,13 @@ import type { AxiosRequestConfig } from 'axios';
import axios from 'axios';
import type { RequestOptions } from 'oauth-1.0a';
import clientOAuth1 from 'oauth-1.0a';

import {
Credentials,
LoadMappingOptions,
LoadNodeParameterOptions,
LoadNodeListSearch,
} from 'n8n-core';

import { Credentials } from 'n8n-core';
import type {
INodeCredentials,
INodeCredentialsDetails,
INodeListSearchResult,
INodeParameters,
INodePropertyOptions,
INodeTypeNameVersion,
WorkflowExecuteMode,
ICredentialTypes,
ExecutionStatus,
IExecutionsSummary,
ResourceMapperFields,
IN8nUISettings,
} from 'n8n-workflow';
import { jsonParse } from 'n8n-workflow';
Expand All @@ -68,18 +55,11 @@ import {
} from '@/constants';
import { credentialsController } from '@/credentials/credentials.controller';
import { oauth2CredentialController } from '@/credentials/oauth2Credential.api';
import type {
CurlHelper,
ExecutionRequest,
NodeListSearchRequest,
NodeParameterOptionsRequest,
OAuthRequest,
ResourceMapperRequest,
WorkflowRequest,
} from '@/requests';
import type { CurlHelper, ExecutionRequest, OAuthRequest, WorkflowRequest } from '@/requests';
import { registerController } from '@/decorators';
import {
AuthController,
DynamicNodeParametersController,
LdapController,
MeController,
MFAController,
Expand Down Expand Up @@ -294,6 +274,7 @@ export class Server extends AbstractServer {
postHog,
),
Container.get(MeController),
Container.get(DynamicNodeParametersController),
new NodeTypesController(config, nodeTypes),
new PasswordResetController(
logger,
Expand Down Expand Up @@ -474,170 +455,6 @@ export class Server extends AbstractServer {
this.logger.warn(`Source Control initialization failed: ${error.message}`);
}

// ----------------------------------------

// Returns parameter values which normally get loaded from an external API or
// get generated dynamically
this.app.get(
`/${this.restEndpoint}/node-parameter-options`,
ResponseHelper.send(
async (req: NodeParameterOptionsRequest): Promise<INodePropertyOptions[]> => {
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;

const { path, methodName } = req.query;

const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;

let credentials: INodeCredentials | undefined;

if (req.query.credentials) {
credentials = jsonParse(req.query.credentials);
}

const loadDataInstance = new LoadNodeParameterOptions(
nodeTypeAndVersion,
this.nodeTypes,
path,
currentNodeParameters,
credentials,
);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
req.user.id,
currentNodeParameters,
);

if (methodName) {
return loadDataInstance.getOptionsViaMethodName(methodName, additionalData);
}
// @ts-ignore
if (req.query.loadOptions) {
return loadDataInstance.getOptionsViaRequestProperty(
// @ts-ignore
jsonParse(req.query.loadOptions as string),
additionalData,
);
}

return [];
},
),
);

// Returns parameter values which normally get loaded from an external API or
// get generated dynamically
this.app.get(
`/${this.restEndpoint}/nodes-list-search`,
ResponseHelper.send(
async (
req: NodeListSearchRequest,
res: express.Response,
): Promise<INodeListSearchResult | undefined> => {
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;

const { path, methodName } = req.query;

if (!req.query.currentNodeParameters) {
throw new ResponseHelper.BadRequestError(
'Parameter currentNodeParameters is required.',
);
}

const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;

let credentials: INodeCredentials | undefined;

if (req.query.credentials) {
credentials = jsonParse(req.query.credentials);
}

const listSearchInstance = new LoadNodeListSearch(
nodeTypeAndVersion,
this.nodeTypes,
path,
currentNodeParameters,
credentials,
);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
req.user.id,
currentNodeParameters,
);

if (methodName) {
return listSearchInstance.getOptionsViaMethodName(
methodName,
additionalData,
req.query.filter,
req.query.paginationToken,
);
}

throw new ResponseHelper.BadRequestError('Parameter methodName is required.');
},
),
);

this.app.get(
`/${this.restEndpoint}/get-mapping-fields`,
ResponseHelper.send(
async (
req: ResourceMapperRequest,
res: express.Response,
): Promise<ResourceMapperFields | undefined> => {
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;

const { path, methodName } = req.query;

if (!req.query.currentNodeParameters) {
throw new ResponseHelper.BadRequestError(
'Parameter currentNodeParameters is required.',
);
}

const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;

let credentials: INodeCredentials | undefined;

if (req.query.credentials) {
credentials = jsonParse(req.query.credentials);
}

const loadMappingOptionsInstance = new LoadMappingOptions(
nodeTypeAndVersion,
this.nodeTypes,
path,
currentNodeParameters,
credentials,
);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
req.user.id,
currentNodeParameters,
);

const fields = await loadMappingOptionsInstance.getOptionsViaMethodName(
methodName,
additionalData,
);

return fields;
},
),
);

// ----------------------------------------
// Active Workflows
// ----------------------------------------
Expand Down
153 changes: 153 additions & 0 deletions packages/cli/src/controllers/dynamicNodeParameters.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { Service } from 'typedi';
import type { RequestHandler } from 'express';
import { NextFunction, Response } from 'express';
import type {
INodeCredentials,
INodeListSearchResult,
INodeParameters,
INodePropertyOptions,
INodeTypeNameVersion,
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 { BadRequestError } from '@/ResponseHelper';
import type { AuthenticatedRequest } from '@/requests';

const assertMethodName: RequestHandler = (req, res, next) => {
const { methodName } = req.query as 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: 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: OptionsRequest): 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: ResourceLocatorResultsRequest,
): 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: ResourceMapperFieldsRequest,
): 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,
);
}
}

type BaseRequest<QueryParams = {}> = AuthenticatedRequest<
{
nodeTypeAndVersion: INodeTypeNameVersion;
currentNodeParameters: INodeParameters;
credentials?: INodeCredentials;
},
{},
{},
{
path: string;
nodeTypeAndVersion: string;
currentNodeParameters: string;
methodName?: string;
credentials?: string;
} & QueryParams
>;

/** GET /dynamic-node-parameters/options */
type OptionsRequest = BaseRequest<{
loadOptions?: string;
}>;

/** GET /dynamic-node-parameters/resource-locator-results */
type ResourceLocatorResultsRequest = BaseRequest<{
methodName: string;
filter?: string;
paginationToken?: string;
}>;

/** GET dynamic-node-parameters/resource-mapper-fields */
type ResourceMapperFieldsRequest = BaseRequest<{
methodName: string;
}>;
1 change: 1 addition & 0 deletions packages/cli/src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { AuthController } from './auth.controller';
export { DynamicNodeParametersController } from './dynamicNodeParameters.controller';
export { LdapController } from './ldap.controller';
export { MeController } from './me.controller';
export { MFAController } from './mfa.controller';
Expand Down
Loading

0 comments on commit 81ac215

Please sign in to comment.