Repository: vapor/vapor
File: Sources/Vapor/Middleware/ErrorMiddleware.swift (Swift)

Code before:
            case let encodable as ResponseEncodable:
                do {
                    return try encodable.encode(for: req)
                } catch { }
                fallthrough
            default:
                // not an abort error, and not debuggable or in dev mode
                // just deliver a generic 500 to avoid exposing any sensitive error info
                reason = "Something went wrong."
                status = .internalServerError
                headers = [:]
            }

            // create a Response with appropriate status
            let res = req.response(http: .init(status: status, headers: headers))

            // attempt to serialize the error to json
            do {
                let errorResponse = ErrorResponse(error: true, reason: reason)
                res.http.body = try HTTPBody(data: JSONEncoder().encode(errorResponse))
                res.http.headers.replaceOrAdd(name: .contentType, value: "application/json; charset=utf-8")
            } catch {
                res.http.body = HTTPBody(string: "Oops: \(error)")
                res.http.headers.replaceOrAdd(name: .contentType, value: "text/plain; charset=utf-8")
            }
            return req.future(res)
        }
    }

    /// Error-handling closure.
    private let closure: (Request, Error) -> (Future<Response>)

    /// Create a new `ErrorMiddleware`.
    ///
    /// - parameters:
    ///     - closure: Error-handling closure. Converts `Error` to `Response`.
    public init(_ closure: @escaping (Request, Error) -> (Future<Response>)) {
        self.closure = closure
    }

    /// See `Middleware`.
    public func respond(to req: Request, chainingTo next: Responder) throws -> Future<Response> {
        let response: Future<Response>
        do {
            response = try next.respond(to: req)
        } catch {
            response = req.eventLoop.newFailedFuture(error: error)
        }

        return response.catchFlatMap { error in
            return self.closure(req, error)

Review comment (suggestion):
I changed the handling closure to return a future, since it was required for the encoding of the `ResponseEncodable`

Code after:
            default:
                // not an abort error, and not debuggable or in dev mode
                // just deliver a generic 500 to avoid exposing any sensitive error info
                reason = "Something went wrong."
                status = .internalServerError
                headers = [:]
            }

            // create a Response with appropriate status
            let res = req.response(http: .init(status: status, headers: headers))

            // attempt to serialize the error to json
            do {
                let errorResponse = ErrorResponse(error: true, reason: reason)
                res.http.body = try HTTPBody(data: JSONEncoder().encode(errorResponse))
                res.http.headers.replaceOrAdd(name: .contentType, value: "application/json; charset=utf-8")
            } catch {
                res.http.body = HTTPBody(string: "Oops: \(error)")
                res.http.headers.replaceOrAdd(name: .contentType, value: "text/plain; charset=utf-8")
            }
            return res
        }
    }

    /// Error-handling closure.
    private let closure: (Request, Error) -> (Response)

    /// Create a new `ErrorMiddleware`.
    ///
    /// - parameters:
    ///     - closure: Error-handling closure. Converts `Error` to `Response`.
    public init(_ closure: @escaping (Request, Error) -> (Response)) {
        self.closure = closure
    }

    /// See `Middleware`.
    public func respond(to req: Request, chainingTo next: Responder) throws -> Future<Response> {
        let response: Future<Response>
        do {
            response = try next.respond(to: req)
        } catch {
            response = req.eventLoop.newFailedFuture(error: error)
        }

        return response.catchFlatMap { error in
            if let response = error as? ResponseEncodable {
                do {
                    return try response.encode(for: req)
                } catch {
                    return req.future(self.closure(req, error))
                }