Merge pull request #425 from trouble/graphql-errors
gql errors include formatted field validation data
This commit is contained in:
@@ -5,11 +5,12 @@ const httpStatus = require('http-status');
|
||||
* @extends Error
|
||||
*/
|
||||
class ExtendableError extends Error {
|
||||
constructor(message, status, isPublic) {
|
||||
constructor(message, status, data, isPublic) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
this.status = status;
|
||||
this.data = data;
|
||||
this.isPublic = isPublic;
|
||||
this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
|
||||
Error.captureStackTrace(this, this.constructor.name);
|
||||
@@ -25,10 +26,11 @@ class APIError extends ExtendableError {
|
||||
* Creates an API error.
|
||||
* @param {string} message - Error message.
|
||||
* @param {number} status - HTTP status code of error.
|
||||
* @param {object} data - response data to be returned.
|
||||
* @param {boolean} isPublic - Whether the message should be visible to user or not.
|
||||
*/
|
||||
constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) {
|
||||
super(message, status, isPublic);
|
||||
constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, data, isPublic = false) {
|
||||
super(message, status, data, isPublic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ const APIError = require('./APIError');
|
||||
|
||||
class ValidationError extends APIError {
|
||||
constructor(results) {
|
||||
super(results, httpStatus.BAD_REQUEST);
|
||||
super(`Bad request with ${results.length} errors`, httpStatus.BAD_REQUEST, results);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
const errorHandler = async (info, debug, afterErrorHook) => {
|
||||
return Promise.all(info.result.errors.map(async (err) => {
|
||||
// TODO: use payload logging
|
||||
console.error(err.stack);
|
||||
/**
|
||||
*
|
||||
* @param info
|
||||
* @param debug
|
||||
* @param afterErrorHook
|
||||
* @returns {Promise<unknown[]>}
|
||||
*/
|
||||
const errorHandler = async (info, debug, afterErrorHook) => Promise.all(info.result.errors.map(async (err) => {
|
||||
// TODO: use payload logging
|
||||
console.error(err.stack);
|
||||
|
||||
let response = {
|
||||
...err,
|
||||
};
|
||||
let response = {
|
||||
message: err.message,
|
||||
data: err?.originalError?.data,
|
||||
};
|
||||
|
||||
if (afterErrorHook) {
|
||||
({ response } = await afterErrorHook(err, response) || { response });
|
||||
}
|
||||
if (afterErrorHook) {
|
||||
({ response } = await afterErrorHook(err, response) || { response });
|
||||
}
|
||||
|
||||
if (debug && debug === true) {
|
||||
response.stack = err.stack;
|
||||
}
|
||||
if (debug && debug === true) {
|
||||
response.stack = err.stack;
|
||||
}
|
||||
|
||||
return response;
|
||||
}));
|
||||
};
|
||||
return response;
|
||||
}));
|
||||
|
||||
module.exports = errorHandler;
|
||||
|
||||
@@ -20,6 +20,7 @@ const initCollections = require('../collections/graphql/init');
|
||||
const initGlobals = require('../globals/graphql/init');
|
||||
const buildWhereInputType = require('./schema/buildWhereInputType');
|
||||
const access = require('../auth/graphql/resolvers/access');
|
||||
const errorHandler = require('./errorHandler');
|
||||
|
||||
class InitializeGraphQL {
|
||||
constructor(init) {
|
||||
@@ -93,31 +94,23 @@ class InitializeGraphQL {
|
||||
|
||||
this.schema = new GraphQLSchema(schema);
|
||||
|
||||
// this.errorExtensions = [];
|
||||
// this.errorExtensionIteration = 0;
|
||||
|
||||
// this.extensions = async (info) => {
|
||||
// const { result } = info;
|
||||
// if (result.errors) {
|
||||
// const afterErrorHook = typeof this.config.hooks.afterError === 'function' ? this.config.hooks.afterError : null;
|
||||
// this.errorExtensions = await errorHandler(info, this.config.debug, afterErrorHook);
|
||||
// }
|
||||
// return null;
|
||||
// };
|
||||
this.extensions = async (info) => {
|
||||
const { result } = info;
|
||||
if (result.errors) {
|
||||
const afterErrorHook = typeof this.config.hooks.afterError === 'function' ? this.config.hooks.afterError : null;
|
||||
this.errorResponse = await errorHandler(info, this.config.debug, afterErrorHook);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
init(req, res) {
|
||||
this.errorResponse = null;
|
||||
return graphQLHTTP(
|
||||
async (request, response, { variables }) => ({
|
||||
schema: this.schema,
|
||||
// customFormatErrorFn: () => {
|
||||
// const response = {
|
||||
// ...this.errorExtensions[this.errorExtensionIteration],
|
||||
// };
|
||||
// this.errorExtensionIteration += 1;
|
||||
// return response;
|
||||
// },
|
||||
// extensions: this.extensions,
|
||||
customFormatErrorFn: () => (this.errorResponse),
|
||||
extensions: this.extensions,
|
||||
context: { req, res },
|
||||
validationRules: [
|
||||
queryComplexity({
|
||||
|
||||
Reference in New Issue
Block a user