From 3cd1ec21e6fdf89d2f5e4a0a3e90238b87115b9a Mon Sep 17 00:00:00 2001 From: martmull Date: Thu, 7 Dec 2023 12:32:29 +0100 Subject: [PATCH] Throw an error if workspace id has no object (#2857) * Throw an error if workspace id has no object * Request only plurial object names * Fix tests * Fix query * Handle graphql errors --- .../self-hosting/enviroment-variables.mdx | 3 ++- server/.env.example | 1 + .../api-rest-query-builder.factory.spec.ts | 2 ++ .../api-rest-query-builder.factory.ts | 22 +++++++++---------- .../src/core/api-rest/api-rest.controller.ts | 2 +- server/src/core/api-rest/api-rest.service.ts | 18 +++++++-------- .../api-rest/types/api-rest-response.type.ts | 2 +- .../environment/environment.service.ts | 4 ++++ .../environment/environment.validation.ts | 5 +++++ 9 files changed, 36 insertions(+), 23 deletions(-) diff --git a/docs/docs/start/self-hosting/enviroment-variables.mdx b/docs/docs/start/self-hosting/enviroment-variables.mdx index 577f6d0622..3e96b20964 100644 --- a/docs/docs/start/self-hosting/enviroment-variables.mdx +++ b/docs/docs/start/self-hosting/enviroment-variables.mdx @@ -27,6 +27,7 @@ import OptionTable from '@site/src/theme/OptionTable' ['REDIS_HOST', '127.0.0.1', 'Redis connection host'], ['REDIS_PORT', '6379', 'Redis connection port'], ['FRONT_BASE_URL', 'http://localhost:3001', 'Url to the hosted frontend'], + ['SERVER_URL', 'http://localhost:3000', 'Url to the hosted server'], ['PORT', '3000', 'Port'], ]}> @@ -97,4 +98,4 @@ import OptionTable from '@site/src/theme/OptionTable' \ No newline at end of file + ]}> diff --git a/server/.env.example b/server/.env.example index e28d5c9b47..c48ee9a041 100644 --- a/server/.env.example +++ b/server/.env.example @@ -30,3 +30,4 @@ SIGN_IN_PREFILLED=true # REDIS_HOST=127.0.0.1 # REDIS_PORT=6379 # DEMO_WORKSPACE_IDS=REPLACE_ME_WITH_A_RANDOM_UUID +# SERVER_URL=http://localhost:3000 diff --git a/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.spec.ts b/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.spec.ts index 47393b37f2..2a27133b64 100644 --- a/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.spec.ts +++ b/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.spec.ts @@ -12,6 +12,7 @@ import { UpdateVariablesFactory } from 'src/core/api-rest/api-rest-query-builder import { GetVariablesFactory } from 'src/core/api-rest/api-rest-query-builder/factories/get-variables.factory'; import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; import { TokenService } from 'src/core/auth/services/token.service'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; describe('ApiRestQueryBuilderFactory', () => { let service: ApiRestQueryBuilderFactory; @@ -31,6 +32,7 @@ describe('ApiRestQueryBuilderFactory', () => { { provide: GetVariablesFactory, useValue: {} }, { provide: ObjectMetadataService, useValue: {} }, { provide: TokenService, useValue: {} }, + { provide: EnvironmentService, useValue: {} }, ], }).compile(); diff --git a/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.ts b/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.ts index 3e959fc1c9..0a95b1e6ea 100644 --- a/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.ts +++ b/server/src/core/api-rest/api-rest-query-builder/api-rest-query-builder.factory.ts @@ -17,6 +17,7 @@ import { parsePath } from 'src/core/api-rest/api-rest-query-builder/utils/parse- import { computeDepth } from 'src/core/api-rest/api-rest-query-builder/utils/compute-depth.utils'; import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity'; import { ApiRestQuery } from 'src/core/api-rest/types/api-rest-query.type'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; @Injectable() export class ApiRestQueryBuilderFactory { @@ -32,6 +33,7 @@ export class ApiRestQueryBuilderFactory { private readonly getVariablesFactory: GetVariablesFactory, private readonly objectMetadataService: ObjectMetadataService, private readonly tokenService: TokenService, + private readonly environmentService: EnvironmentService, ) {} async getObjectMetadata(request: Request): Promise<{ @@ -43,29 +45,27 @@ export class ApiRestQueryBuilderFactory { const objectMetadataItems = await this.objectMetadataService.findManyWithinWorkspace(workspaceId); - const { id, object: parsedObject } = parsePath(request); - - let objectNameKey = 'namePlural'; - let wrongObjectNameKey = 'nameSingular'; - - if (id) { - objectNameKey = 'nameSingular'; - wrongObjectNameKey = 'namePlural'; + if (!objectMetadataItems.length) { + throw new BadRequestException( + `No object was found for the workspace associated with this API key. You may generate a new one here ${this.environmentService.getFrontBaseUrl()}/settings/developers/api-keys`, + ); } + const { object: parsedObject } = parsePath(request); + const [objectMetadata] = objectMetadataItems.filter( - (object) => object[objectNameKey] === parsedObject, + (object) => object.namePlural === parsedObject, ); if (!objectMetadata) { const [wrongObjectMetadata] = objectMetadataItems.filter( - (object) => object[wrongObjectNameKey] === parsedObject, + (object) => object.nameSingular === parsedObject, ); let hint = 'eg: companies'; if (wrongObjectMetadata) { - hint = `Did you mean '${wrongObjectMetadata[objectNameKey]}'?`; + hint = `Did you mean '${wrongObjectMetadata.namePlural}'?`; } throw new BadRequestException( diff --git a/server/src/core/api-rest/api-rest.controller.ts b/server/src/core/api-rest/api-rest.controller.ts index 7fb3e69f76..12f2efedbc 100644 --- a/server/src/core/api-rest/api-rest.controller.ts +++ b/server/src/core/api-rest/api-rest.controller.ts @@ -7,7 +7,7 @@ import { ApiRestResponse } from 'src/core/api-rest/types/api-rest-response.type' const handleResult = (res: Response, result: ApiRestResponse) => { if (result.data.error) { - res.status(400).send(result.data); + res.status(result.data.status || 400).send({ error: result.data.error }); } else { res.send(result.data); } diff --git a/server/src/core/api-rest/api-rest.service.ts b/server/src/core/api-rest/api-rest.service.ts index 5d1136dc64..25a9be5d49 100644 --- a/server/src/core/api-rest/api-rest.service.ts +++ b/server/src/core/api-rest/api-rest.service.ts @@ -21,15 +21,15 @@ export class ApiRestService { request: Request, data: ApiRestQuery, ): Promise { - return await axios.post( - `${request.protocol}://${request.get('host')}/graphql`, - data, - { - headers: { - Authorization: request.headers.authorization, - }, + const baseUrl = + this.environmentService.getServerUrl() || + `${request.protocol}://${request.get('host')}`; + + return await axios.post(`${baseUrl}/graphql`, data, { + headers: { + Authorization: request.headers.authorization, }, - ); + }); } async get(request: Request): Promise { @@ -38,7 +38,7 @@ export class ApiRestService { return await this.callGraphql(request, data); } catch (err) { - return { data: { error: `${err}` } }; + return { data: { error: `${err}`, status: err.response.status } }; } } diff --git a/server/src/core/api-rest/types/api-rest-response.type.ts b/server/src/core/api-rest/types/api-rest-response.type.ts index 6e2d0dec10..231264126e 100644 --- a/server/src/core/api-rest/types/api-rest-response.type.ts +++ b/server/src/core/api-rest/types/api-rest-response.type.ts @@ -1 +1 @@ -export type ApiRestResponse = { data: { error?: string } }; +export type ApiRestResponse = { data: { error?: string; status?: number } }; diff --git a/server/src/integrations/environment/environment.service.ts b/server/src/integrations/environment/environment.service.ts index b19d9697f9..cc3868fb63 100644 --- a/server/src/integrations/environment/environment.service.ts +++ b/server/src/integrations/environment/environment.service.ts @@ -50,6 +50,10 @@ export class EnvironmentService { return this.configService.get('FRONT_BASE_URL')!; } + getServerUrl(): string { + return this.configService.get('SERVER_URL')!; + } + getAccessTokenSecret(): string { return this.configService.get('ACCESS_TOKEN_SECRET')!; } diff --git a/server/src/integrations/environment/environment.validation.ts b/server/src/integrations/environment/environment.validation.ts index 0361a9099d..9f07586bc0 100644 --- a/server/src/integrations/environment/environment.validation.ts +++ b/server/src/integrations/environment/environment.validation.ts @@ -60,6 +60,11 @@ export class EnvironmentVariables { @IsUrl({ require_tld: false }) FRONT_BASE_URL: string; + // Frontend URL + @IsUrl({ require_tld: false }) + @IsOptional() + SERVER_URL: string; + // Json Web Token @IsString() ACCESS_TOKEN_SECRET: string;