Last active
August 18, 2020 12:41
-
-
Save jtodaone/2404b3aeda5e7c826cc992cf968ebc78 to your computer and use it in GitHub Desktop.
Vapor ErrorUIMiddleware - It's for Vapor 3. It is outdated, and likely not to work with Vapor 4.
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
import Vapor | |
public final class ErrorUIMiddleware: Middleware, Service { | |
private struct ErrorResponseBody { | |
private init() {} | |
static let templateKitError = errorMessage("UI rendering failed", "sorry, an error occured while rendering UI.") | |
static let errorMessage: (String, String...) -> String = { (title: String, messages: String...) in | |
var returnMessage = "<h1>\(title)</h1>" | |
for message in messages { | |
returnMessage += "<p>\(message)</p>" | |
} | |
return returnMessage | |
} | |
} | |
public func respond(to request: Request, chainingTo next: Responder) throws -> Future<Response> { | |
do { | |
return try next.respond(to: request).flatMap { response in | |
if response.http.status.code >= 400 { | |
return try self.presentErrorView(for: request, error: Abort(response.http.status)) | |
} else { | |
return try response.encode(for: request) | |
} | |
}.catchFlatMap { try self.presentErrorView(for: request, error: $0) } | |
} catch { | |
return try presentErrorView(for: request, error: error) | |
} | |
} | |
private func presentErrorView(for request: Request, error: Error) throws -> Future<Response> { | |
do { | |
let logger = try request.make(Logger.self) | |
switch error { | |
case _ where error is AbortError && (error as! AbortError).status == .notFound: | |
return try renderErrorView(for: request, error: error as! AbortError) | |
case _ where error is AbortError: | |
let abortError = error as! AbortError | |
logger.report(error: abortError) | |
return try renderErrorView(for: request, error: error as! AbortError) | |
default: | |
logger.report(error: error) | |
return try renderErrorView(for: request, error: Abort(.internalServerError)) | |
} | |
} catch { | |
print("Internal Server Error while rendering error view: \(error.localizedDescription)") | |
return try renderErrorView(for: request, error: Abort(.internalServerError)) | |
} | |
} | |
private func renderErrorView(for request: Request, error: AbortError) throws -> Future<Response> { | |
let errorContext = ErrorContext(code: error.status.code, description: error.reason) | |
return try request.view().render("error", ["error": errorContext]).encode(status: error.status, for: request).catchFlatMap { _ in | |
return ErrorResponseBody.templateKitError.encode(status: error.status, for: request).map { response in | |
response.http.contentType = MediaType.html | |
return response | |
} | |
} | |
} | |
private struct ErrorContext: Content { | |
let code: UInt | |
let description: String | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to configure:
ErrorUIMiddleware
as service byservices.register(ErrorUIMiddleware())
.middlewares.use(ErrorUIMiddleware.self)
.