chore: 🤖 add convenience identifiers to error objects

This commit is contained in:
Randall Morey committed 2020-06-17 12:12:32 -04:00
1 parent e092ac54f6
commit dc20d6ef02
2 files changed
+68 -5

No files matched your search

+49
View File
@@ -4,6 +4,7 @@ import { get } from '@ember/object';
import { InvalidError } from '@ember-data/adapter/error';
import { dasherize } from '@ember/string';
import { pluralize } from 'ember-inflector';
import { isArray } from '@ember/array';
export default class ApplicationAdapter extends RESTAdapter {
// =attributes
@@ -91,6 +92,53 @@ export default class ApplicationAdapter extends RESTAdapter {
return super.handleResponse(status, headers, payload, requestData);
}
/**
* Add convenience booleans to each error within the errors list indicating
* the type of error that occurred. This is useful in downstream templates,
* e.g. `{{if error.isForbidden}}`.
*
* Error booleans are attached based on the error status code:
*
* - `401 isUnauthenticated`: the session isn't authenticated
* - `403 isForbidden`: the session is authenticated but does not have
* permission to perform the requested action
* - `404 isNotFound`: the requested resource could not be found
* - `500 isServer`: an internal server error occurred
* - `isUnknown`: an error occurred, but we don't know which or
* we don't distinguish it yet
*
* @override
* @method normalizeErrorResponse
* @param {Number} status
* @param {Object} headers
* @param {Object} payload
* @return {Array} errors payload
*/
normalizeErrorResponse(/*status, headers, payload*/) {
const errors = super.normalizeErrorResponse(...arguments);
if (isArray(errors)) {
errors.forEach(error => {
switch (Number(error.status)) {
case 401:
error.isUnauthenticated = true;
break;
case 403:
error.isForbidden = true;
break;
case 404:
error.isNotFound = true;
break;
case 500:
error.isServer = true;
break;
default:
error.isUnknown = true;
}
});
}
return errors;
}
/**
* Normalizes the errors found in a payload from our API into JSON API
* error format.
@@ -103,6 +151,7 @@ export default class ApplicationAdapter extends RESTAdapter {
// Normalize the primary error message into "base", which is an error
// that applies to the whole model instance
const baseError = {
isInvalid: true,
status: payload.source,
code: payload.code,
detail: payload.message,
@@ -38,23 +38,37 @@ module('Unit | Adapter | application', function (hooks) {
});
test('it returns an proper InvalidError from handleResponse', function (assert) {
assert.expect(3);
assert.expect(4);
const adapter = this.owner.lookup('adapter:application');
let payload = {
const payload = {
status: 400,
code: 'invalid_argument',
message: 'The request was invalid.',
};
let handledResponse = adapter.handleResponse(400, {}, payload);
const handledResponse = adapter.handleResponse(400, {}, payload);
assert.ok(handledResponse instanceof InvalidError);
assert.equal(handledResponse.errors.length, 1);
assert.equal(handledResponse.message, 'The request was invalid.');
assert.ok(handledResponse.errors[0].isInvalid);
});
test('it assigns convenience booleans for error types', function (assert) {
assert.expect(6);
const adapter = this.owner.lookup('adapter:application');
const getResponse = (status) =>
adapter.handleResponse(status, {}, { status });
assert.ok(getResponse(401).errors[0].isUnauthenticated);
assert.ok(getResponse(403).errors[0].isForbidden);
assert.ok(getResponse(404).errors[0].isNotFound);
assert.ok(getResponse(500).errors[0].isServer);
assert.ok(getResponse(0).errors[0].isUnknown);
assert.ok(getResponse(false).errors[0].isUnknown);
});
test('it returns field-level errors in InvalidError from handleResponse', function (assert) {
assert.expect(1);
const adapter = this.owner.lookup('adapter:application');
let payload = {
const payload = {
status: 400,
code: 'invalid_argument',
message: 'The request was invalid.',
@@ -62,7 +76,7 @@ module('Unit | Adapter | application', function (hooks) {
fields: [{ name: 'name', message: 'Name is wrong.' }],
},
};
let handledResponse = adapter.handleResponse(400, {}, payload);
const handledResponse = adapter.handleResponse(400, {}, payload);
assert.equal(
handledResponse.errors.length,
2,