Skip to content

Commit

Permalink
Output errors as JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-fowler committed Apr 30, 2024
1 parent 6bfd41f commit 00294d9
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
6 changes: 3 additions & 3 deletions Sources/HummingbirdCore/Error/HTTPError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public struct HTTPError: Error, HTTPResponseError, Sendable {
public var status: HTTPResponse.Status
/// any addiitional headers required
public var headers: HTTPFields
/// error payload, assumed to be a string
/// error message
public var body: String?

/// Initialize HTTPError
Expand All @@ -39,13 +39,13 @@ public struct HTTPError: Error, HTTPResponseError, Sendable {
/// - message: Associated message
public init(_ status: HTTPResponse.Status, message: String) {
self.status = status
self.headers = [.contentType: "text/plain; charset=utf-8"]
self.headers = [.contentType: "application/json; charset=utf-8"]
self.body = message
}

/// Get body of error as ByteBuffer
public func body(allocator: ByteBufferAllocator) -> ByteBuffer? {
return self.body.map { allocator.buffer(string: $0) }
return self.body.map { allocator.buffer(string: "{\"error\":{\"message\":\"\($0)\"}}\n") }
}
}

Expand Down
11 changes: 10 additions & 1 deletion Tests/HummingbirdRouterTests/MiddlewareTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ final class MiddlewareTests: XCTestCase {
}

func testMiddlewareRunWhenNoRouteFound() async throws {
/// Error message returned by Hummingbird
struct ErrorMessage: Codable {
struct Details: Codable {
let message: String
}

let error: Details
}
struct TestMiddleware<Context: BaseRequestContext>: RouterMiddleware {
func handle(_ request: Request, context: Context, next: (Request, Context) async throws -> Response) async throws -> Response {
do {
Expand All @@ -114,8 +122,9 @@ final class MiddlewareTests: XCTestCase {

try await app.test(.router) { client in
try await client.execute(uri: "/hello", method: .get) { response in
XCTAssertEqual(String(buffer: response.body), "Edited error")
XCTAssertEqual(response.status, .notFound)
let error = try JSONDecoder().decode(ErrorMessage.self, from: response.body)
XCTAssertEqual(error.error.message, "Edited error")
}
}
}
Expand Down
22 changes: 22 additions & 0 deletions Tests/HummingbirdTests/ApplicationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,28 @@ final class ApplicationTests: XCTestCase {
}
}

func testErrorOutput() async throws {
/// Error message returned by Hummingbird
struct ErrorMessage: Codable {
struct Details: Codable {
let message: String
}

let error: Details
}
let router = Router()
router.get("error") { _, _ -> HTTPResponse.Status in
throw HTTPError(.badRequest, message: "BAD!")
}
let app = Application(router: router)
try await app.test(.router) { client in
try await client.execute(uri: "/error", method: .get) { response in
let error = try JSONDecoder().decode(ErrorMessage.self, from: response.body)
XCTAssertEqual(error.error.message, "BAD!")
}
}
}

func testResponseBody() async throws {
let router = Router()
router
Expand Down
11 changes: 10 additions & 1 deletion Tests/HummingbirdTests/MiddlewareTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ final class MiddlewareTests: XCTestCase {
}

func testMiddlewareRunWhenNoRouteFound() async throws {
/// Error message returned by Hummingbird
struct ErrorMessage: Codable {
struct Details: Codable {
let message: String
}

let error: Details
}
struct TestMiddleware<Context: BaseRequestContext>: RouterMiddleware {
public func handle(_ request: Request, context: Context, next: (Request, Context) async throws -> Response) async throws -> Response {
do {
Expand All @@ -106,8 +114,9 @@ final class MiddlewareTests: XCTestCase {

try await app.test(.router) { client in
try await client.execute(uri: "/hello", method: .get) { response in
XCTAssertEqual(String(buffer: response.body), "Edited error")
XCTAssertEqual(response.status, .notFound)
let error = try JSONDecoder().decode(ErrorMessage.self, from: response.body)
XCTAssertEqual(error.error.message, "Edited error")
}
}
}
Expand Down

0 comments on commit 00294d9

Please sign in to comment.