diff --git a/api/decorators/index.ts b/api/decorators/index.ts new file mode 100644 index 0000000..4481e6e --- /dev/null +++ b/api/decorators/index.ts @@ -0,0 +1,46 @@ +export function IsNotEmpty( + target: any, + methodName: string, + parameterIndex: number +) { + if (!target?.validations) { + target.validations = []; + } + + target.validations.push(`${methodName}:${parameterIndex}:${IsNotEmpty.name}`); +} + +function IsNotEmptyValidate( + methodName: string, + argumentIndex: number, + argumentValue: any +) { + if (argumentValue === '' || argumentValue === null || argumentValue === undefined) { + throw new Error(`Invalid empty argument at index ${argumentIndex} with "${argumentValue}" value in "${methodName}" method`); + } +} + +export function Validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor) { + let method = descriptor.value!; + + descriptor.value = function (...args: Array) { + if (target?.validations?.length) { + for (const validation of target.validations) { + const [methodName, argumentIndex, validatorName] = validation.split(":"); + + if (method.name === methodName) { + switch (validatorName) { + case IsNotEmpty.name: + const argumentValue = args[argumentIndex]; + + IsNotEmptyValidate(methodName, argumentIndex, argumentValue); + + break; + } + } + } + } + + return method.apply(this, arguments); + }; +} diff --git a/api/projects/index.ts b/api/projects/index.ts index 16eeae2..824de57 100644 --- a/api/projects/index.ts +++ b/api/projects/index.ts @@ -2,6 +2,7 @@ import { SmartlingBaseApi } from "../base/index"; import { SmartlingAuthApi } from "../auth/index"; import { Logger } from "../logger"; import { ProjectDto } from "./dto/project-dto"; +import { IsNotEmpty, Validate } from "../decorators"; export class SmartlingProjectsApi extends SmartlingBaseApi { constructor(smartlingApiBaseUrl: string, authApi: SmartlingAuthApi, logger: Logger) { @@ -10,7 +11,8 @@ export class SmartlingProjectsApi extends SmartlingBaseApi { this.entrypoint = `${smartlingApiBaseUrl}/projects-api/v2/projects`; } - async getProjectDetails(projectId: string): Promise { + @Validate + async getProjectDetails(@IsNotEmpty projectId: string): Promise { return await this.makeRequest( "get", `${this.entrypoint}/${projectId}` diff --git a/index.ts b/index.ts index b7fa455..ada425f 100644 --- a/index.ts +++ b/index.ts @@ -103,3 +103,4 @@ export * from "./api/locales/dto/direction"; export * from "./api/locales/dto/word-delimeter"; export * from "./api/locales/params/get-locales-parameters"; export * from "./api/locales/index"; +export * from "./api/decorators/index"; diff --git a/test/projects.spec.ts b/test/projects.spec.ts index ac3bb4d..38b0cc0 100644 --- a/test/projects.spec.ts +++ b/test/projects.spec.ts @@ -2,6 +2,7 @@ import sinon from "sinon"; import { SmartlingProjectsApi } from "../api/projects/index"; import { loggerMock, authMock, responseMock } from "./mock"; import { SmartlingAuthApi } from "../api/auth/index"; +import assert from "assert"; describe("SmartlingProjectsApi class tests.", () => { const projectId = "testProjectId"; @@ -47,5 +48,25 @@ describe("SmartlingProjectsApi class tests.", () => { } ); }); + + describe("IsNotEmpty decorator test", () => { + it("Empty string", async () => { + await assert.rejects(async () => { + await projectsApi.getProjectDetails("") + }, new Error('Invalid empty argument at index 0 with "" value in "getProjectDetails" method')); + }); + + it("null string", async () => { + await assert.rejects(async () => { + await projectsApi.getProjectDetails(null) + }, new Error('Invalid empty argument at index 0 with "null" value in "getProjectDetails" method')); + }); + + it("undefined string", async () => { + await assert.rejects(async () => { + await projectsApi.getProjectDetails(undefined) + }, new Error('Invalid empty argument at index 0 with "undefined" value in "getProjectDetails" method')); + }); + }); }); });