Reputation: 6730
I'm putting together authentication using vapor, and wondered if there's a good way to re-use logic in the routing to be used over rest api as well as a web front end.
struct AuthenticationController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.group("auth") { auth in
auth.post("register", use: register)
auth.post("login", use: login)
}
auth.group("email-verification") { emailVerificationRoutes in
emailVerificationRoutes.post("", use: sendEmailVerification)
emailVerificationRoutes.get("", use: verifyEmail)
}
...
}
private func register(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
...
}
private func login(_ req: Request) throws -> EventLoopFuture<LoginResponse> {
...
}
...
}
I'm then adding this auth collection under api
app.group("api") { api in
try! api.register(collection: AuthenticationController())
}
All the return values are EventLoopFutures
of either HTTPStatus
when there's nothing to return, or structs that implement Content
to return objects as json
What I'm wondering is how would be a good way to refactor out and resuse anything in auth and apply html web interfaces for it as well? So web forms for the post bits, pages for get, error responses etc. that could be served under /auth/login
etc. as well as /api/auth/login
I was thinking I might be able to flatMap
or similar the EventLoopFuture
s returned in the methods, and convert those by returning View
s but I'm not sure how I'd go about that.
Or would it be a case of just pulling out all the logic from AuthenticationController
, and making a WebAuthenticationController
route collection for example that builds similar routes with the handlers in both controllers calling out to the logic handlers?
I've tried searching but wasn't able to find any examples of reusing handlers for multiple purposes
Upvotes: 1
Views: 70
Reputation: 5084
Well you could create a new struct conforming to ResponseEncodable
like this:
struct MixedResponse: ResponseEncodable {
var view: View?
var response: Response?
static func view(_ view: View) -> MixedResponse {
MixedResponse(view: view)
}
static func response(_ response: Response) -> MixedResponse {
MixedResponse(response: response)
}
}
Then in your encodeResponse
function check what is nill
& return the relevant data:
func encodeResponse(for request: Request) -> EventLoopFuture<Response> {
if let view {
//do something
}else if let response {
//do something
}
}
Instead of returning a specific response, you just return MixedResponse
. I highly encourage you to try async/await
instead of Futures.
Upvotes: 1