Skip to content

Commit

Permalink
feat: use objection error types in error-handler (#131)
Browse files Browse the repository at this point in the history
* new error handler

* feat: use objection errors in error-handler

* cleanup commented out lines

* revert package lock

* add better error messages

* update readme

* fix: NotNullViolationError message

* update tests that rely on original error message

* Fixed typo in test description

Co-authored-by: Dekel Barzilay <dekelev@gmail.com>
  • Loading branch information
robbyphillips and dekelev committed Nov 21, 2020
1 parent 14d7209 commit da66fc7
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 273 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,6 @@ you now have full CRUD for your new todos service!
and to [seed](http://knexjs.org/#Seeds) a table with mock data.
## Error handling
As of version 4.8.0, `feathers-objection` only throws [Feathers Errors](https://docs.feathersjs.com/api/errors.html)
with the message.
On the server, the original error can be retrieved through a secure symbol via `error[require('feathers-objection').ERROR]`.
Expand All @@ -845,6 +844,10 @@ try {
}
```
As of version 7.0.0, `feathers-objection` has normalized errors accross all databases supported by Objection, and makes a best-effort attempt to provide reasonable error messages that can be returned directly to the client.
If these error messages do not work for your needs, the original error is still available using the symbol described above.
## Migrating to `feathers-objection` v2
`feathers-objection` 2.0.0 comes with important security and usability updates
Expand Down Expand Up @@ -887,6 +890,17 @@ The following breaking changes have been introduced:
- `patch` method now enforce `params.query` with upsert
- NotFound error will be thrown when `get` & `update` methods are called with different values in `id` & `params.query.id`
## Migrating to `feathers-objection` v7
`feathers-objection` 7.0.0 comes with improved error handling.
The following breaking changes have been introduced:
- All Databases will return the same types of errors based on the underlying Objection error
- SQL Driver error text is no longer used as the Feathers error message
- Objection errors are mapped more accurately to Feathers errors, e.g.
- Objection's `UniqueViolationError` -> Feathers' `Conflict` error type
## License
Copyright © 2020
Expand Down
151 changes: 59 additions & 92 deletions src/error-handler.js
Original file line number Diff line number Diff line change
@@ -1,108 +1,75 @@
import errors from '@feathersjs/errors';
import {
ValidationError,
NotFoundError,
DBError,
ConstraintViolationError,
UniqueViolationError,
NotNullViolationError,
ForeignKeyViolationError,
CheckViolationError,
DataError
} from 'objection';

const ERROR = Symbol('feathers-knex/error');

export default function errorHandler (error) {
const { message } = error.nativeError || error;
let feathersError = error;
let feathersError;

if (error.code === 'SQLITE_ERROR') {
switch (error.errno) {
case 1:
case 8:
case 18:
case 19:
case 20:
feathersError = new errors.BadRequest(message);
if (error instanceof errors.FeathersError) {
feathersError = error;
} else if (error instanceof ValidationError) {
switch (error.type) {
case 'ModelValidation':
feathersError = new errors.BadRequest(message, error.data);
break;
case 2:
feathersError = new errors.Unavailable(message);
case 'RelationExpression':
feathersError = new errors.BadRequest('Invalid Relation Expression');
break;
case 3:
case 23:
feathersError = new errors.Forbidden(message);
case 'UnallowedRelation':
feathersError = new errors.BadRequest('Unallowed Relation Expression');
break;
case 12:
feathersError = new errors.NotFound(message);
case 'InvalidGraph':
feathersError = new errors.BadRequest('Invalid Relation Graph');
break;
default:
feathersError = new errors.GeneralError(message);
break;
}
} else if (error.statusCode) { // Objection validation error
switch (error.statusCode) {
case 400:
feathersError = new errors.BadRequest(message);
break;

case 401:
feathersError = new errors.NotAuthenticated(message);
break;

case 402:
feathersError = new errors.PaymentError(message);
break;

case 403:
feathersError = new errors.Forbidden(message);
break;

case 404:
feathersError = new errors.NotFound(message);
break;

case 405:
feathersError = new errors.MethodNotAllowed(message);
break;

case 406:
feathersError = new errors.NotAcceptable(message);
break;

case 408:
feathersError = new errors.Timeout(message);
break;

case 409:
feathersError = new errors.Conflict(message);
break;

case 422:
feathersError = new errors.Unprocessable(message);
break;

case 501:
feathersError = new errors.NotImplemented(message);
break;

case 503:
feathersError = new errors.Unavailable(message);
break;

case 500:
default:
feathersError = new errors.GeneralError(message);
}
} else if (typeof error.code === 'string') { // Postgres error code - TODO: Properly detect postgres error
const pgerror = error.code.substring(0, 2);

switch (pgerror) {
case '28':
case '42':
feathersError = new errors.Forbidden(message);
break;

case '20':
case '21':
case '22':
case '23':
feathersError = new errors.BadRequest(message);
break;

default:
feathersError = new errors.GeneralError(message);
feathersError = new errors.BadRequest('Unknown Validation Error');
}
} else if (!(error instanceof errors.FeathersError)) {
} else if (error instanceof NotFoundError) {
feathersError = new errors.NotFound(message);
} else if (error instanceof UniqueViolationError) {
feathersError = new errors.Conflict(`${error.columns.join(', ')} must be unique`, {
columns: error.columns,
table: error.table,
constraint: error.constraint
});
} else if (error instanceof NotNullViolationError) {
feathersError = new errors.BadRequest(`${error.column} must not be null`, {
column: error.column,
table: error.table
});
} else if (error instanceof ForeignKeyViolationError) {
feathersError = new errors.Conflict('Foreign Key Violation', {
table: error.table,
constraint: error.constraint
});
} else if (error instanceof CheckViolationError) {
feathersError = new errors.BadRequest('Check Violation', {
table: error.table,
constraint: error.constraint
});
} else if (error instanceof ConstraintViolationError) {
feathersError = new errors.Conflict('Constraint Violation', {
columns: error.columns,
table: error.table,
constraint: error.constraint
});
} else if (error instanceof DataError) {
feathersError = new errors.BadRequest('Invalid Data');
} else if (error instanceof DBError) {
feathersError = new errors.GeneralError('Unknown Database Error');
} else {
feathersError = new errors.GeneralError(message);
}

Expand Down
Loading

0 comments on commit da66fc7

Please sign in to comment.