From 1aa0f867241a0725a241348150524f2eea1fd10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20M?= Date: Thu, 11 Jan 2024 10:21:51 +0100 Subject: [PATCH] feat: use apollo playground in debug mode (#3295) --- .../src/graphql-config.service.ts | 15 ++++- .../src/metadata/metadata.module-factory.ts | 57 ++++++++++++------- .../src/metadata/metadata.module.ts | 3 +- .../utils/render-apollo-playground.util.ts | 25 ++++++++ 4 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 packages/twenty-server/src/workspace/utils/render-apollo-playground.util.ts diff --git a/packages/twenty-server/src/graphql-config.service.ts b/packages/twenty-server/src/graphql-config.service.ts index 40b36198f..fa18d6532 100644 --- a/packages/twenty-server/src/graphql-config.service.ts +++ b/packages/twenty-server/src/graphql-config.service.ts @@ -21,6 +21,8 @@ import { Workspace } from 'src/core/workspace/workspace.entity'; import { WorkspaceFactory } from 'src/workspace/workspace.factory'; import { ExceptionHandlerService } from 'src/integrations/exception-handler/exception-handler.service'; import { handleExceptionAndConvertToGraphQLError } from 'src/filters/utils/global-exception-handler.util'; +import { renderApolloPlayground } from 'src/workspace/utils/render-apollo-playground.util'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; @Injectable() export class GraphQLConfigService @@ -29,13 +31,14 @@ export class GraphQLConfigService constructor( private readonly tokenService: TokenService, private readonly exceptionHandlerService: ExceptionHandlerService, + private readonly environmentService: EnvironmentService, private readonly moduleRef: ModuleRef, ) {} createGqlOptions(): YogaDriverConfig { const exceptionHandlerService = this.exceptionHandlerService; - - return { + const isDebugMode = this.environmentService.isDebugMode(); + const config: YogaDriverConfig = { context: ({ req }) => ({ req }), autoSchemaFile: true, include: [CoreModule], @@ -90,6 +93,14 @@ export class GraphQLConfigService resolvers: { JSON: GraphQLJSON }, plugins: [], }; + + if (isDebugMode) { + config.renderGraphiQL = () => { + return renderApolloPlayground(); + }; + } + + return config; } async createSchema( diff --git a/packages/twenty-server/src/metadata/metadata.module-factory.ts b/packages/twenty-server/src/metadata/metadata.module-factory.ts index 47eb99179..175347843 100644 --- a/packages/twenty-server/src/metadata/metadata.module-factory.ts +++ b/packages/twenty-server/src/metadata/metadata.module-factory.ts @@ -1,32 +1,47 @@ -import { YogaDriver, YogaDriverConfig } from '@graphql-yoga/nestjs'; +import { YogaDriverConfig } from '@graphql-yoga/nestjs'; import { GraphQLError } from 'graphql'; import GraphQLJSON from 'graphql-type-json'; import { maskError } from 'graphql-yoga'; import { handleExceptionAndConvertToGraphQLError } from 'src/filters/utils/global-exception-handler.util'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; import { ExceptionHandlerService } from 'src/integrations/exception-handler/exception-handler.service'; import { MetadataModule } from 'src/metadata/metadata.module'; +import { renderApolloPlayground } from 'src/workspace/utils/render-apollo-playground.util'; export const metadataModuleFactory = async ( + environmentService: EnvironmentService, exceptionHandlerService: ExceptionHandlerService, -): Promise => ({ - context: ({ req }) => ({ req }), - driver: YogaDriver, - autoSchemaFile: true, - include: [MetadataModule], - resolvers: { JSON: GraphQLJSON }, - plugins: [], - path: '/metadata', - maskedErrors: { - maskError(error: GraphQLError, message, isDev) { - if (error.originalError) { - return handleExceptionAndConvertToGraphQLError( - error.originalError, - exceptionHandlerService, - ); - } - - return maskError(error, message, isDev); +): Promise => { + const config: YogaDriverConfig = { + context: ({ req }) => ({ req }), + autoSchemaFile: true, + include: [MetadataModule], + renderGraphiQL() { + return renderApolloPlayground({ path: 'metadata' }); }, - }, -}); + resolvers: { JSON: GraphQLJSON }, + plugins: [], + path: '/metadata', + maskedErrors: { + maskError(error: GraphQLError, message, isDev) { + if (error.originalError) { + return handleExceptionAndConvertToGraphQLError( + error.originalError, + exceptionHandlerService, + ); + } + + return maskError(error, message, isDev); + }, + }, + }; + + if (environmentService.isDebugMode()) { + config.renderGraphiQL = () => { + return renderApolloPlayground({ path: 'metadata' }); + }; + } + + return config; +}; diff --git a/packages/twenty-server/src/metadata/metadata.module.ts b/packages/twenty-server/src/metadata/metadata.module.ts index 50091e686..27692ccff 100644 --- a/packages/twenty-server/src/metadata/metadata.module.ts +++ b/packages/twenty-server/src/metadata/metadata.module.ts @@ -7,6 +7,7 @@ import { WorkspaceMigrationRunnerModule } from 'src/workspace/workspace-migratio import { WorkspaceMigrationModule } from 'src/metadata/workspace-migration/workspace-migration.module'; import { metadataModuleFactory } from 'src/metadata/metadata.module-factory'; import { ExceptionHandlerService } from 'src/integrations/exception-handler/exception-handler.service'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; import { DataSourceModule } from './data-source/data-source.module'; import { FieldMetadataModule } from './field-metadata/field-metadata.module'; @@ -16,8 +17,8 @@ import { RelationMetadataModule } from './relation-metadata/relation-metadata.mo imports: [ GraphQLModule.forRootAsync({ driver: YogaDriver, - inject: [ExceptionHandlerService], useFactory: metadataModuleFactory, + inject: [EnvironmentService, ExceptionHandlerService], }), DataSourceModule, FieldMetadataModule, diff --git a/packages/twenty-server/src/workspace/utils/render-apollo-playground.util.ts b/packages/twenty-server/src/workspace/utils/render-apollo-playground.util.ts new file mode 100644 index 000000000..f33d866b3 --- /dev/null +++ b/packages/twenty-server/src/workspace/utils/render-apollo-playground.util.ts @@ -0,0 +1,25 @@ +interface ApolloPlaygroundOptions { + path?: string; +} + +export const renderApolloPlayground = ({ + path = 'graphql', +}: ApolloPlaygroundOptions = {}) => { + return ` + + + +
+ + + + `; +};