From ebb124de4b1d29e3baa9f686ddaa55eec935d702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20No=C3=ABl?= Date: Fri, 29 Oct 2021 12:23:28 +0200 Subject: [PATCH] change graphql error handling with originalError --- packages/core/utils/lib/errors.js | 5 +-- .../graphql/server/format-graphql-error.js | 40 ++++++++++++++++++- .../plugins/i18n/server/services/core-api.js | 15 +++---- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/packages/core/utils/lib/errors.js b/packages/core/utils/lib/errors.js index 4c758a23e4..4c96d4a808 100644 --- a/packages/core/utils/lib/errors.js +++ b/packages/core/utils/lib/errors.js @@ -20,18 +20,17 @@ class ValidationError extends ApplicationError { } } -class YupValidationError extends ApplicationError { +class YupValidationError extends ValidationError { constructor(yupError, message) { super(); const { errors, message: yupMessage } = formatYupErrors(yupError); - this.name = 'ValidationError'; this.message = message || yupMessage; this.details = { errors }; } } class PaginationError extends ApplicationError { - constructor(message, details = {}) { + constructor(message, details) { super(message, details); this.name = 'PaginationError'; this.message = message || 'Invalid pagination'; diff --git a/packages/plugins/graphql/server/format-graphql-error.js b/packages/plugins/graphql/server/format-graphql-error.js index 4bb167b54b..a0c0a7ab4e 100644 --- a/packages/plugins/graphql/server/format-graphql-error.js +++ b/packages/plugins/graphql/server/format-graphql-error.js @@ -1,8 +1,44 @@ 'use strict'; -const formatGraphqlError = error => { - delete error.extensions.code; +const { toUpper, snakeCase } = require('lodash/fp'); +const { + HttpError, + ForbiddenError, + UnauthorizedError, + ApplicationError, + ValidationError, +} = require('@strapi/utils').errors; +const { + ApolloError, + UserInputError: ApolloUserInputError, + ForbiddenError: ApolloForbiddenError, +} = require('apollo-server-errors'); +const formatToCode = name => `STRAPI_${toUpper(snakeCase(name))}`; + +const formatGraphqlError = error => { + const originalError = error.originalError; + + if (originalError instanceof ApolloError) { + return error; + } + + if (originalError instanceof ForbiddenError || originalError instanceof UnauthorizedError) { + return new ApolloForbiddenError(originalError.message, { details: originalError.details }); + } + + if (originalError instanceof ValidationError) { + return new ApolloUserInputError(originalError.message, { details: originalError.details }); + } + + if (originalError instanceof ApplicationError || originalError instanceof HttpError) { + const name = formatToCode(originalError.name); + return new ApolloError(originalError.message, name, { details: originalError.details }); + } + + // Internal server error + strapi.log.error(error); + error.message = 'An error occured'; return error; }; diff --git a/packages/plugins/i18n/server/services/core-api.js b/packages/plugins/i18n/server/services/core-api.js index c4d37cc157..a7e5436b49 100644 --- a/packages/plugins/i18n/server/services/core-api.js +++ b/packages/plugins/i18n/server/services/core-api.js @@ -3,6 +3,7 @@ const _ = require('lodash'); const { prop, pick, reduce, map, keys, toPath, isNil } = require('lodash/fp'); const { contentTypes, parseMultipartData, sanitizeEntity } = require('@strapi/utils'); +const { ApplicationError, NotFoundError } = require('@strapi/utils').errors; const { getService } = require('../utils'); @@ -94,7 +95,7 @@ const createLocalizationHandler = contentType => { }; }; -const createCreateLocalizationHandler = contentType => async (ctx = {}) => { +const createCreateLocalizationHandler = contentType => async (args = {}) => { const { copyNonLocalizedAttributes } = getService('content-types'); const { sanitizeInput, sanitizeInputFiles } = createSanitizer(contentType); @@ -103,28 +104,28 @@ const createCreateLocalizationHandler = contentType => async (ctx = {}) => { ? await strapi.query(contentType.uid).findOne({ populate: ['localizations'] }) : await strapi .query(contentType.uid) - .findOne({ where: { id: ctx.id }, populate: ['localizations'] }); + .findOne({ where: { id: args.id }, populate: ['localizations'] }); if (!entry) { - return ctx.notFound('baseEntryId.invalid'); + throw new NotFoundError(); } - const { data, files } = ctx; + const { data, files } = args; const { findByCode } = getService('locales'); if (isNil(data.locale)) { - return ctx.badRequest('locale.missing'); + throw new ApplicationError('locale is missing'); } const matchingLocale = await findByCode(data.locale); if (!matchingLocale) { - return ctx.badRequest('locale.invalid'); + throw new ApplicationError('locale is invalid'); } const usedLocales = getAllLocales(entry); if (usedLocales.includes(data.locale)) { - return ctx.badRequest('locale.already.used'); + throw new ApplicationError('locale is already used'); } const sanitizedData = {