Skip to content

Commit 95427cd

Browse files
committed
Added specializations to APIErrorMiddleware for converting specific errors to a custom message
1 parent 82b8842 commit 95427cd

File tree

1 file changed

+28
-20
lines changed

1 file changed

+28
-20
lines changed

Sources/APIErrorMiddleware/APIErrorMiddleware.swift

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ import Foundation
99
/// a 404 status code.
1010
public final class APIErrorMiddleware: Middleware, Service, ServiceType {
1111

12+
/// Specializations for converting specific errors
13+
/// to `ErrorResult` objects.
14+
let specializations: [ErrorCatchingSpecialization]
15+
1216
// We define an empty init because the one
1317
// synthesized bby Swift is marked `internal`.
1418

1519
/// Create an instance if `APIErrorMiddleware`.
16-
public init() {}
20+
public init(specializations: [ErrorCatchingSpecialization] = []) {
21+
self.specializations = specializations
22+
}
1723

1824
/// Creates a service instance. Used by a `ServiceFactory`.
1925
public static func makeService(for worker: Container) throws -> APIErrorMiddleware {
@@ -59,47 +65,49 @@ public final class APIErrorMiddleware: Middleware, Service, ServiceType {
5965
/// - Returns: A response with a JSON body with a `{"error":<error>}` structure.
6066
private func response(for error: Error, with request: Request) -> Response {
6167

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!
6472

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+
}
6784

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 {
7686

7787
// We have an `AbortError` which has both a
7888
// status code and error message.
7989
// 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 {
8392

8493
// We have some other error.
8594
// Set the message to the error's `description`.
8695
let error = error as CustomStringConvertible
87-
message = error.description
88-
status = nil
96+
result = ErrorResult(message: error.description, status: nil)
8997
}
9098

9199
// Create JSON with an `error` key with the `message` constant as its value.
92100
// We default to no data instead of throwing, because we don't want any errors
93101
// 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()
95103

96104
// Create an HTTPResponse with
97105
// - The detected status code, using
98106
// 400 (Bad Request) if one does not exist.
99107
// - A `application/json` Content Type header.
100108
// A body with the JSON we created.
101109
let httpResponse = HTTPResponse(
102-
status: status ?? .badRequest,
110+
status: result.status ?? .badRequest,
103111
headers: ["Content-Type": "application/json"],
104112
body: HTTPBody(data: json)
105113
)

0 commit comments

Comments
 (0)