refactor(server): dont convert graphql bad request into internal server error (#10203)

This commit is contained in:
fengmk2
2025-02-17 06:17:00 +00:00
parent 34472fdfa9
commit 57213781a8
7 changed files with 66 additions and 9 deletions
@@ -251,6 +251,12 @@ export const USER_FRIENDLY_ERRORS = {
type: 'bad_request',
message: 'Bad request.',
},
graphql_bad_request: {
type: 'bad_request',
args: { code: 'string', message: 'string' },
message: ({ code, message }) =>
`GraphQL bad request, code: ${code}, ${message}`,
},
// Input errors
query_too_long: {
@@ -28,6 +28,17 @@ export class BadRequest extends UserFriendlyError {
}
}
@ObjectType()
class GraphqlBadRequestDataType {
@Field() code!: string
@Field() message!: string
}
export class GraphqlBadRequest extends UserFriendlyError {
constructor(args: GraphqlBadRequestDataType, message?: string | ((args: GraphqlBadRequestDataType) => string)) {
super('bad_request', 'graphql_bad_request', message, args);
}
}
@ObjectType()
class QueryTooLongDataType {
@Field() max!: number
}
@@ -787,6 +798,7 @@ export enum ErrorNames {
TOO_MANY_REQUEST,
NOT_FOUND,
BAD_REQUEST,
GRAPHQL_BAD_REQUEST,
QUERY_TOO_LONG,
USER_NOT_FOUND,
USER_AVATAR_NOT_FOUND,
@@ -891,5 +903,5 @@ registerEnumType(ErrorNames, {
export const ErrorDataUnionType = createUnionType({
name: 'ErrorDataUnion',
types: () =>
[QueryTooLongDataType, WrongSignInCredentialsDataType, UnknownOauthProviderDataType, MissingOauthQueryParameterDataType, InvalidEmailDataType, InvalidPasswordLengthDataType, WorkspacePermissionNotFoundDataType, SpaceNotFoundDataType, MemberNotFoundInSpaceDataType, NotInSpaceDataType, AlreadyInSpaceDataType, SpaceAccessDeniedDataType, SpaceOwnerNotFoundDataType, SpaceShouldHaveOnlyOneOwnerDataType, DocNotFoundDataType, DocAccessDeniedDataType, VersionRejectedDataType, InvalidHistoryTimestampDataType, DocHistoryNotFoundDataType, BlobNotFoundDataType, ExpectToGrantDocUserRolesDataType, ExpectToRevokeDocUserRolesDataType, ExpectToUpdateDocUserRoleDataType, UnsupportedSubscriptionPlanDataType, SubscriptionAlreadyExistsDataType, SubscriptionNotExistsDataType, SameSubscriptionRecurringDataType, SubscriptionPlanNotFoundDataType, CopilotDocNotFoundDataType, CopilotMessageNotFoundDataType, CopilotPromptNotFoundDataType, CopilotProviderSideErrorDataType, CopilotInvalidContextDataType, CopilotContextFileNotSupportedDataType, CopilotFailedToModifyContextDataType, CopilotFailedToMatchContextDataType, RuntimeConfigNotFoundDataType, InvalidRuntimeConfigTypeDataType, InvalidLicenseUpdateParamsDataType, WorkspaceMembersExceedLimitToDowngradeDataType] as const,
[GraphqlBadRequestDataType, QueryTooLongDataType, WrongSignInCredentialsDataType, UnknownOauthProviderDataType, MissingOauthQueryParameterDataType, InvalidEmailDataType, InvalidPasswordLengthDataType, WorkspacePermissionNotFoundDataType, SpaceNotFoundDataType, MemberNotFoundInSpaceDataType, NotInSpaceDataType, AlreadyInSpaceDataType, SpaceAccessDeniedDataType, SpaceOwnerNotFoundDataType, SpaceShouldHaveOnlyOneOwnerDataType, DocNotFoundDataType, DocAccessDeniedDataType, VersionRejectedDataType, InvalidHistoryTimestampDataType, DocHistoryNotFoundDataType, BlobNotFoundDataType, ExpectToGrantDocUserRolesDataType, ExpectToRevokeDocUserRolesDataType, ExpectToUpdateDocUserRoleDataType, UnsupportedSubscriptionPlanDataType, SubscriptionAlreadyExistsDataType, SubscriptionNotExistsDataType, SameSubscriptionRecurringDataType, SubscriptionPlanNotFoundDataType, CopilotDocNotFoundDataType, CopilotMessageNotFoundDataType, CopilotPromptNotFoundDataType, CopilotProviderSideErrorDataType, CopilotInvalidContextDataType, CopilotContextFileNotSupportedDataType, CopilotFailedToModifyContextDataType, CopilotFailedToMatchContextDataType, RuntimeConfigNotFoundDataType, InvalidRuntimeConfigTypeDataType, InvalidLicenseUpdateParamsDataType, WorkspaceMembersExceedLimitToDowngradeDataType] as const,
});
@@ -38,9 +38,7 @@ export class GQLLoggerPlugin implements ApolloServerPlugin {
},
didEncounterErrors: ctx => {
ctx.errors.forEach(gqlErr => {
const error = mapAnyError(
gqlErr.originalError ? gqlErr.originalError : gqlErr
);
const error = mapAnyError(gqlErr);
error.log('GraphQL');
metrics.gql.counter('query_error_counter').add(1, {
@@ -1,3 +1,4 @@
import { ApolloServerErrorCode } from '@apollo/server/errors';
import {
ArgumentsHost,
Catch,
@@ -9,10 +10,12 @@ import { GqlContextType } from '@nestjs/graphql';
import { ThrottlerException } from '@nestjs/throttler';
import { BaseWsExceptionFilter } from '@nestjs/websockets';
import { Response } from 'express';
import { GraphQLError } from 'graphql';
import { of } from 'rxjs';
import { Socket } from 'socket.io';
import {
GraphqlBadRequest,
InternalServerError,
NotFound,
TooManyRequest,
@@ -21,7 +24,28 @@ import {
import { metrics } from '../metrics';
import { getRequestIdFromHost } from '../utils';
function isGraphQLBadRequest(error: any): error is GraphQLError {
// https://www.apollographql.com/docs/apollo-server/data/errors
const code = error.extensions?.code;
return (
code === ApolloServerErrorCode.GRAPHQL_PARSE_FAILED ||
code === ApolloServerErrorCode.GRAPHQL_VALIDATION_FAILED ||
code === ApolloServerErrorCode.BAD_USER_INPUT ||
code === ApolloServerErrorCode.BAD_REQUEST
);
}
export function mapAnyError(error: any): UserFriendlyError {
if (error instanceof GraphQLError) {
const err = error;
if (isGraphQLBadRequest(error)) {
return new GraphqlBadRequest({
code: err.extensions.code as string,
message: err.message,
});
}
error = err.originalError ?? error;
}
if (error instanceof UserFriendlyError) {
return error;
} else if (error instanceof ThrottlerException) {