diff --git a/PapyrusCore/Sources/Response.swift b/PapyrusCore/Sources/Response.swift index 7651fc7..46506ed 100644 --- a/PapyrusCore/Sources/Response.swift +++ b/PapyrusCore/Sources/Response.swift @@ -8,29 +8,32 @@ public protocol Response { } extension Response { + /// Validates the status code of a Response, as well as any transport errors that may have occurred. @discardableResult public func validate() throws -> Self { - if let statusCode { - guard (200..<300).contains(statusCode) else { - throw PapyrusError("Unsuccessful status code: \(statusCode).") - } - } - - guard let error else { - return self + if let error { throw error } + if let statusCode, !(200..<300).contains(statusCode) { throw PapyrusError("Unsuccessful status code: \(statusCode).") } + return self + } + + public func decode(_ type: Data?.Type = Data?.self, using decoder: ResponseDecoder) throws -> Data? { + try validate().body + } + + public func decode(_ type: Data.Type = Data.self, using decoder: ResponseDecoder) throws -> Data { + guard let body = try decode(Data?.self, using: decoder) else { + throw PapyrusError("Unable to return the body of a `Response`; the body was nil.") } - throw error + return body } - + public func decode(_ type: D.Type = D.self, using decoder: ResponseDecoder) throws -> D { - try validate() - - guard let data = body else { + guard let body = try validate().body else { throw PapyrusError("Unable to decode `\(Self.self)` from a `Response`; body was nil.") } - - return try decoder.decode(type, from: data) + + return try decoder.decode(type, from: body) } } diff --git a/README.md b/README.md index 7db802d..bbe655d 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,22 @@ Endpoint functions should return a type that conforms to `Decodable`. It will au func getUser() async throws -> User ``` +### Accessing just the body + +If you only need a response's raw body bytes, you can just return `Data` from your function. + +```swift +@GET("/bytes") +func getBytes() async throws -> Data +``` + +The above will throw if the request body is empty, even if the status code is successful. If you don't want to throw in that case, set the response as `Data?`; it will successfully return nil if the response body is empty. + +```swift +@GET("/bytes") +func getBytes() async throws -> Data? +``` + ### Empty responses If you don't need to decode something from the response and just want to confirm it was successful, you may leave out the return type.