Skip to content

Instantly share code, notes, and snippets.

@Andrew-Lees11
Created March 6, 2019 14:41
Show Gist options
  • Save Andrew-Lees11/c4de32e04e7017372d0e7852d7cf4539 to your computer and use it in GitHub Desktop.
Save Andrew-Lees11/c4de32e04e7017372d0e7852d7cf4539 to your computer and use it in GitHub Desktop.
Codable Routing with Result
// 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