@@ -9,11 +9,17 @@ import Foundation
9
9
/// a 404 status code.
10
10
public final class APIErrorMiddleware : Middleware , Service , ServiceType {
11
11
12
+ /// Specializations for converting specific errors
13
+ /// to `ErrorResult` objects.
14
+ let specializations : [ ErrorCatchingSpecialization ]
15
+
12
16
// We define an empty init because the one
13
17
// synthesized bby Swift is marked `internal`.
14
18
15
19
/// Create an instance if `APIErrorMiddleware`.
16
- public init ( ) { }
20
+ public init ( specializations: [ ErrorCatchingSpecialization ] = [ ] ) {
21
+ self . specializations = specializations
22
+ }
17
23
18
24
/// Creates a service instance. Used by a `ServiceFactory`.
19
25
public static func makeService( for worker: Container ) throws -> APIErrorMiddleware {
@@ -59,47 +65,49 @@ public final class APIErrorMiddleware: Middleware, Service, ServiceType {
59
65
/// - Returns: A response with a JSON body with a `{"error":<error>}` structure.
60
66
private func response( for error: Error , with request: Request ) -> Response {
61
67
62
- // The value for the JSON `error` key.
63
- let message : String
68
+ // The error message and status code
69
+ // for the response returned by the
70
+ // middleware.
71
+ var result : ErrorResult !
64
72
65
- // The status code of the response.
66
- let status : HTTPStatus ?
73
+ // Loop through the specializations, running
74
+ // the error converter on each one.
75
+ for converter in self . specializations {
76
+ if let formatted = converter. convert ( error: error, on: request) {
77
+
78
+ // Found a non-nil response. Save it a break
79
+ // from the loop so we don't override it.
80
+ result = formatted
81
+ break
82
+ }
83
+ }
67
84
68
- if let error = error as? Debuggable , error. identifier == " modelNotFound " {
69
-
70
- // We have the infamous `modelNotFound` error from Fluent that returns
71
- // a 500 status code instead of a 404.
72
- // Set the message to the error's `reason` and the status to 404 (Not Found)
73
- message = error. reason
74
- status = . notFound
75
- } else if let error = error as? AbortError {
85
+ if result == nil , let error = error as? AbortError {
76
86
77
87
// We have an `AbortError` which has both a
78
88
// status code and error message.
79
89
// Assign the data to the correct varaibles.
80
- message = error. reason
81
- status = error. status
82
- } else {
90
+ result = ErrorResult ( message: error. reason, status: error. status)
91
+ } else if result == nil {
83
92
84
93
// We have some other error.
85
94
// Set the message to the error's `description`.
86
95
let error = error as CustomStringConvertible
87
- message = error. description
88
- status = nil
96
+ result = ErrorResult ( message: error. description, status: nil )
89
97
}
90
98
91
99
// Create JSON with an `error` key with the `message` constant as its value.
92
100
// We default to no data instead of throwing, because we don't want any errors
93
101
// leaving the middleware body.
94
- let json = ( try ? JSONEncoder ( ) . encode ( [ " error " : message] ) ) ?? message. data ( using: . utf8) ?? Data ( )
102
+ let json = ( try ? JSONEncoder ( ) . encode ( [ " error " : result . message] ) ) ?? result . message. data ( using: . utf8) ?? Data ( )
95
103
96
104
// Create an HTTPResponse with
97
105
// - The detected status code, using
98
106
// 400 (Bad Request) if one does not exist.
99
107
// - A `application/json` Content Type header.
100
108
// A body with the JSON we created.
101
109
let httpResponse = HTTPResponse (
102
- status: status ?? . badRequest,
110
+ status: result . status ?? . badRequest,
103
111
headers: [ " Content-Type " : " application/json " ] ,
104
112
body: HTTPBody ( data: json)
105
113
)
0 commit comments