Skip to content

Instantly share code, notes, and snippets.

@jtodaone
Last active August 18, 2020 12:41
Show Gist options
  • Save jtodaone/2404b3aeda5e7c826cc992cf968ebc78 to your computer and use it in GitHub Desktop.
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.
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
}
}
@jtodaone
Copy link
Author

How to configure:

  1. Register ErrorUIMiddleware as service by services.register(ErrorUIMiddleware()).
  2. Then register it as middleware by middlewares.use(ErrorUIMiddleware.self).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment