Last active
March 15, 2019 21:14
-
-
Save emarashliev/820f37726cc02b38b04f306d8b1c0f2d to your computer and use it in GitHub Desktop.
Vapor Middleware that catches thrown errors and translate them. The preferred language should be passed by `Accept-Language` header
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 NStack | |
import Vapor | |
import Sugar | |
protocol Translatable { | |
var translationKey: String { get } | |
} | |
extension AuthenticationError: Translatable { | |
var translationKey: String { | |
switch self { | |
case .signingError, .userNotFound, .weakPassword, .usernameAlreadyExists, .incorrectPassword: | |
return rawValue | |
default: return "GenericAuthenticationErrorKey" | |
} | |
} | |
} | |
struct TranslatedError: AbortError { | |
let identifier: String | |
let reason: String | |
let status: HTTPResponseStatus | |
} | |
public final class TranslateMiddleware: Middleware, ServiceType { | |
public static func makeService(for worker: Container) throws -> TranslateMiddleware { | |
return .default() | |
} | |
public static func `default`() -> TranslateMiddleware { | |
return .init() | |
} | |
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 | |
guard let translatableError = error as? Translatable else { | |
throw error | |
} | |
let translationKey = translatableError.translationKey | |
let nstack: NStack = try req.make() | |
let language = req.http.headers.firstValue(name: .acceptLanguage) | |
let errorFuture = nstack.application.translate.get( | |
on: req, | |
platform: .backend, | |
language: language, | |
section: "errors", | |
key: translationKey | |
) | |
return errorFuture.map{ errorString in | |
switch error { | |
case let abortError as AbortError: | |
throw TranslatedError( | |
identifier: abortError.identifier, | |
reason: errorString, | |
status: abortError.status | |
) | |
default: | |
fatalError("You need to cover all the cases of translatable Errors") | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment