mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Added user friendly error messages to Admin API
refs #10438 - Adds new fields to errors returned from API: help, code, and id - Makes `message` more descriptive towards non technical users
This commit is contained in:
parent
4db2eb7ce1
commit
50ea7f0eff
5 changed files with 102 additions and 3 deletions
|
@ -79,7 +79,8 @@ const http = (apiImpl, apiType) => {
|
|||
debug('json response');
|
||||
res.json(result || {});
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(({err, docName, method}) => {
|
||||
req.frameOptions = {docName, method};
|
||||
next(err);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -156,6 +156,9 @@ const pipeline = (apiController, apiUtils) => {
|
|||
})
|
||||
.then(() => {
|
||||
return frame.response;
|
||||
})
|
||||
.catch((err) => {
|
||||
throw {err, docName, method};
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
},
|
||||
"clients": {
|
||||
"clientNotFound": "Client not found"
|
||||
},
|
||||
"actions": {
|
||||
"upload": {
|
||||
"image": "upload image"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -472,6 +477,29 @@
|
|||
"oembed": {
|
||||
"noUrlProvided": "No url provided.",
|
||||
"unknownProvider": "No provider found for supplied URL."
|
||||
},
|
||||
"userMessages": {
|
||||
"InternalServerError": "Internal server error, cannot {action}.",
|
||||
"IncorrectUsageError": "Incorrect usage error, cannot {action}.",
|
||||
"NotFoundError": "Resource not found error, cannot {action}.",
|
||||
"BadRequestError": "Request not understood error, cannot {action}.",
|
||||
"UnauthorizedError": "Authorisation error, cannot {action}.",
|
||||
"NoPermissionError": "Permission error, cannot {action}.",
|
||||
"ValidationError": "Validation error, cannot {action}.",
|
||||
"UnsupportedMediaTypeError": "Unsupported media error, cannot {action}.",
|
||||
"TooManyRequestsError": "Too many requests error, cannot {action}.",
|
||||
"MaintenanceError": "Server down for maintenance, cannot {action}.",
|
||||
"MethodNotAllowedError": "Method not allowed, cannot {action}.",
|
||||
"RequestEntityTooLargeError": "Request too large, cannot {action}.",
|
||||
"TokenRevocationError": "Token is not available, cannot {action}.",
|
||||
"VersionMismatchError": "Version mismatch error, cannot {action}.",
|
||||
"DataExportError": "Error exporting content.",
|
||||
"DataImportError": "Duplicated entry, cannot save {action}.",
|
||||
"DatabaseVersionError": "Database version compatibility error, cannot {action}.",
|
||||
"EmailError": "Error sending email!",
|
||||
"ThemeValidationError": "Theme validation error, cannot {action}.",
|
||||
"DisabledFeatureError": "Theme validation error, the {{{helperName}}} helper is not available. Cannot {action}.",
|
||||
"UpdateCollisionError": "Saving failed! Someone else is editing this post."
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
|
|
|
@ -33,7 +33,7 @@ module.exports = function setupApiApp() {
|
|||
|
||||
// API error handling
|
||||
apiApp.use(shared.middlewares.errorHandler.resourceNotFound);
|
||||
apiApp.use(shared.middlewares.errorHandler.handleJSONResponse);
|
||||
apiApp.use(shared.middlewares.errorHandler.handleJSONResponseV2);
|
||||
|
||||
debug('Admin API v2 setup end');
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const hbs = require('express-hbs');
|
||||
const _ = require('lodash');
|
||||
const debug = require('ghost-ignition').debug('error-handler');
|
||||
const config = require('../../../config');
|
||||
const common = require('../../../lib/common');
|
||||
|
@ -62,7 +63,6 @@ _private.prepareError = (err, req, res, next) => {
|
|||
};
|
||||
|
||||
_private.JSONErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
|
||||
// @TODO: jsonapi errors format (http://jsonapi.org/format/#error-objects)
|
||||
res.json({
|
||||
errors: [{
|
||||
message: err.message,
|
||||
|
@ -73,6 +73,66 @@ _private.JSONErrorRenderer = (err, req, res, next) => { // eslint-disable-line n
|
|||
});
|
||||
};
|
||||
|
||||
_private.prepareUserMessage = (err, res) => {
|
||||
const userError = {
|
||||
message: err.message,
|
||||
context: err.context
|
||||
};
|
||||
|
||||
const docName = _.get(res, 'frameOptions.docName');
|
||||
const method = _.get(res, 'frameOptions.method');
|
||||
|
||||
if (docName && method) {
|
||||
let action;
|
||||
|
||||
const actionMap = {
|
||||
browse: 'list',
|
||||
read: 'read',
|
||||
add: 'save',
|
||||
edit: 'edit',
|
||||
destroy: 'delete'
|
||||
};
|
||||
|
||||
if (common.i18n.doesTranslationKeyExist(`common.api.actions.${docName}.${method}`)) {
|
||||
action = common.i18n.t(`common.api.actions.${docName}.${method}`);
|
||||
} else if (Object.keys(actionMap).includes(method)) {
|
||||
let resource = docName;
|
||||
|
||||
if (method !== 'browse') {
|
||||
resource = resource.replace(/s$/, '');
|
||||
}
|
||||
|
||||
action = `${actionMap[method]} ${resource}`;
|
||||
}
|
||||
|
||||
if (action) {
|
||||
if (err.context) {
|
||||
userError.context = `${err.message} ${err.context}`;
|
||||
}
|
||||
|
||||
userError.message = common.i18n.t(`errors.api.userMessages.${err.name}`, {action: action});
|
||||
}
|
||||
}
|
||||
|
||||
return userError;
|
||||
};
|
||||
|
||||
_private.JSONErrorRendererV2 = (err, req, res, next) => { // eslint-disable-line no-unused-vars
|
||||
const userError = _private.prepareUserMessage(err, req);
|
||||
|
||||
res.json({
|
||||
errors: [{
|
||||
message: userError.message || null,
|
||||
context: userError.context || null,
|
||||
type: err.errorType || null,
|
||||
details: err.errorDetails || null,
|
||||
help: err.help || null,
|
||||
code: err.code || null,
|
||||
id: err.id || null
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
_private.ErrorFallbackMessage = err => `<h1>${common.i18n.t('errors.errors.oopsErrorTemplateHasError')}</h1>
|
||||
<p>${common.i18n.t('errors.errors.encounteredError')}</p>
|
||||
<pre>${escapeExpression(err.message || err)}</pre>
|
||||
|
@ -180,6 +240,13 @@ errorHandler.handleJSONResponse = [
|
|||
_private.JSONErrorRenderer
|
||||
];
|
||||
|
||||
errorHandler.handleJSONResponseV2 = [
|
||||
// Make sure the error can be served
|
||||
_private.prepareError,
|
||||
// Render the error using JSON format
|
||||
_private.JSONErrorRendererV2
|
||||
];
|
||||
|
||||
errorHandler.handleHTMLResponse = [
|
||||
// Make sure the error can be served
|
||||
_private.prepareError,
|
||||
|
|
Loading…
Add table
Reference in a new issue