Framework:
struct Request {
var body: String
}
struct Response {
var status: String
var body: String
}
protocol ResponderType {
func respond(request: Request) throws -> Response
}
struct Responder: ResponderType {
let respond: (request: Request) throws -> Response
func respond(request: Request) throws -> Response {
return try respond(request: request)
}
}
protocol MiddlewareType {
func respond(request: Request, nextResponder: ResponderType) throws -> Response
}
infix operator | { associativity right }
func |(middleware: MiddlewareType, responder: ResponderType) -> ResponderType {
return Responder { request in
return try middleware.respond(request, nextResponder: responder)
}
}
func chain(middlewares: MiddlewareType..., responder: ResponderType) -> ResponderType {
var responder = responder
for middleware in middlewares.reverse() {
responder = middleware | responder
}
return responder
}
Logger Middleware:
struct LoggerMiddleware: MiddlewareType {
func respond(request: Request, nextResponder: ResponderType) throws -> Response {
let response = try nextResponder.respond(request)
print(request)
print(response)
return response
}
}
let logger = LoggerMiddleware()
Authenticator Middleware:
struct AuthenticatorMiddleware: MiddlewareType {
func respond(request: Request, nextResponder: ResponderType) throws -> Response {
if request.body == "password" {
return try nextResponder.respond(request)
} else {
return Response(status: "Unauthorized", body: "You shall not pass!")
}
}
}
let authenticator = AuthenticatorMiddleware()
Template Render Middleware:
struct TemplateRenderMiddleware: MiddlewareType {
func respond(request: Request, nextResponder: ResponderType) throws -> Response {
var response = try nextResponder.respond(request)
response.body = "rendered body"
return response
}
}
let templateRender = TemplateRenderMiddleware()
Usage:
let responder = Responder { _ in
return Response(status: "OK", body: "body")
}
let requestA = Request(body: "password")
let chainA = logger | authenticator | templateRender | responder
try! chainA.respond(requestA)
let requestB = Request(body: "passworder")
let chainB = chain(logger, authenticator, templateRender, responder: responder)
try! chainB.respond(requestB)
Output:
Request(body: "password")
Response(status: "OK", body: "rendered body")
Request(body: "passworder")
Response(status: "Unauthorized", body: "You shall not pass!")