HTTP exceptions
An exception that extends IHttpException turns into an HTTP error answer.
You can throw it or return it from a middleware or a controller.
IHttpException is in packages/dox-annotation/lib/src/core_annotation.dart:
abstract class IHttpException {
int code = 500;
String errorCode = 'server_error';
dynamic message = 'Server Error';
dynamic toResponse() {
if (message is Map) {
return message;
}
return <String, dynamic>{'code': errorCode, 'message': message.toString()};
}
}
The classes
Every class takes the named parameters message, errorCode and code. The table shows the defaults.
| Class | Package | Status code |
errorCode |
Default message |
Dox throws it when |
|---|---|---|---|---|---|
BadRequestException |
dox_core |
400 |
bad_request |
Bad Request |
the body can not be read, like JSON that is not valid |
UnAuthorizedException |
dox_auth |
401 |
unauthorized |
Authentication failed |
AuthMiddleware finds no valid token |
NotFoundHttpException |
dox_core |
404 |
not_found |
Not Found |
a typed path param does not fit ({id} is not an int) |
PayloadTooLargeException |
dox_core |
413 |
payload_too_large |
Payload Too Large |
the body is bigger than maxBodySize or maxMultipartSize |
UnsupportedMediaTypeException |
dox_core |
415 |
unsupported_media_type |
Unsupported Media Type |
a DTO reads a body that is not JSON and not form data |
ValidationException |
dox_core |
422 |
validation_failed |
{} (a Map) |
a DTO or req.validate() finds bad input |
InternalErrorException |
dox_core |
500 |
server_error |
Server Error |
never by itself; for your own use |
QueryException |
dox_core |
500 |
sql_query_error |
Error in sql query |
never by itself; for your own use |
Source files: packages/dox-core/lib/exception/*.dart and packages/dox-auth/lib/src/auth_exception.dart.
What the client gets
responseDataHandler in packages/dox-core/lib/http/http_response_handler.dart sends the answer:
- The status is set to
code. - The body is
toResponse(). - The body is sent as JSON with
Content-Type: application/json.
A text message gives a JSON body with the errorCode and the message:
HTTP/1.1 404 Not Found
content-type: application/json
{"code":"not_found","message":"Blog not found"}
A Map message is sent as it is, with no code key. ValidationException always has a map, one entry per field:
HTTP/1.1 422 Unprocessable Entity
content-type: application/json
{"email":"The email is not a valid email","name":"The name is required"}
A request for a path that has no route answers like a NotFoundHttpException with the message <METHOD> <path> not found: {"code":"not_found","message":"GET /nothing not found"}. Your responseHandler gets it too, so you can change its shape.
To send your own JSON shape from one exception, pass a map:
throw NotFoundHttpException(
message: <String, dynamic>{'error': 'not_found', 'message': 'Blog not found'},
);
Other errors: any Exception or Error that is not an IHttpException gets 500 with error.toString() as text body. It is also passed to errorHandler in AppConfig. An IHttpException is not passed to errorHandler.
A ValidationException from dox_validation (thrown by schema.parse() in a controller) is turned into the 422 ValidationException of dox_core with the same errors.
Make your own
Extend IHttpException and set the three fields in the constructor:
import 'dart:io';
import 'package:dox_core/dox_core.dart';
class ForbiddenException extends IHttpException {
ForbiddenException({
dynamic message = 'Forbidden',
String errorCode = 'forbidden',
int code = HttpStatus.forbidden,
}) {
super.code = code;
super.errorCode = errorCode;
super.message = message;
}
}
Use it:
Future<dynamic> destroy(DoxRequest req, int id) async {
if (req.auth?.user<User>()?.id != id) {
throw ForbiddenException();
}
}
Override toResponse() when every error of your app should have the same JSON shape:
class ApiException extends IHttpException {
ApiException(int code, String errorCode, String message) {
super.code = code;
super.errorCode = errorCode;
super.message = message;
}
@override
dynamic toResponse() {
return <String, dynamic>{'code': errorCode, 'message': message};
}
}
More examples are on the Response page.