Skip to content

Instantly share code, notes, and snippets.

@paulofaria
Last active December 31, 2015 19:15
Show Gist options
  • Save paulofaria/d93b2b0ac1e4204f5c32 to your computer and use it in GitHub Desktop.
Save paulofaria/d93b2b0ac1e4204f5c32 to your computer and use it in GitHub Desktop.

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!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment