Created
March 6, 2019 14:41
-
-
Save Andrew-Lees11/c4de32e04e7017372d0e7852d7cf4539 to your computer and use it in GitHub Desktop.
Codable Routing with Result
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Shared code | |
struct User: Codable { | |
let name: String | |
let age: Int | |
} | |
router.post("/users", handler: postHandler) | |
// Users codable route without result | |
func postHandler(user: User, completion: (User?, RequestError?) -> Void ) { | |
guard user.name == "Andy" else { | |
return respondWith(nil, .badRequest) | |
} | |
completion(user, nil) | |
} | |
// Users codable route with result | |
func postHandler(user: User, completion: (Result<User, RequestError>) -> Void ) { | |
guard user.name == "Andy" else { | |
return respondWith(.failure(.badRequest)) | |
} | |
completion(.success(user)) | |
} | |
// Our Code changes | |
// In KituraContracts | |
public typealias CodableResultClosure<O: Codable> = (O?, RequestError?) -> Void | |
// Becomes | |
public typealias CodableResultClosure<O: Codable> = (Result<O, RequestError>) -> Void | |
// In Kitura | |
public static func constructOutResultHandler<OutputType: Codable>(successStatus: HTTPStatusCode = .OK, response: RouterResponse, completion: @escaping () -> Void) -> CodableResultClosure<OutputType> { | |
return { codableOutput, error in | |
var status = successStatus | |
if let error = error { | |
status = httpStatusCode(from: error) | |
} | |
response.status(status) | |
if status.class != .successful, let error = error { | |
do { | |
if let bodyData = try error.encodeBody(.json) { | |
response.headers.setType("json") | |
response.send(data: bodyData) | |
} | |
} catch { | |
Log.error("Could not encode error: \(error)") | |
response.status(.internalServerError) | |
} | |
} else { | |
if let codableOutput = codableOutput { | |
response.send(codableOutput) | |
} else { | |
Log.debug("Note: successful response ('\(status)') delivers no data.") | |
} | |
} | |
completion() | |
} | |
} | |
// Becomes | |
public static func constructOutResultHandler<OutputType: Codable>(response: RouterResponse, completion: @escaping () -> Void) -> CodableResultClosure<OutputType> { | |
return { result in | |
switch result { | |
case .success(let codableOutput): | |
response.send(codableOutput) | |
case .failure(let error): | |
response.status(httpStatusCode(from: error)) | |
do { | |
if let bodyData = try error.encodeBody(.json) { | |
response.headers.setType("json") | |
response.send(data: bodyData) | |
} | |
} catch { | |
Log.error("Could not encode error: \(error)") | |
response.status(.internalServerError) | |
} | |
} | |
completion() | |
} | |
} | |
// The checking for optional has gone and we no longer have to cater for the (nil,nil) or (codable, .success) case |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment