let drop = Droplet() // 1
try? addProvider(VaporPostgreSQL.Provider.self) // 2
drop.preparations += Model.self // 3
drop.middleware.insert(RedirectMiddleWare(), at: 0) // 4
drop.middleware.append(GzipMiddleWare()) // 5
drop.middleware.append(HeadersMiddleware())
drop.get("/test", handler: {request in
print("4")
return try JSON(node: "This is a test page.")
})
func respond(to request: Request, chainingTo next: Responder) throws -> Response
struct RedirectMiddleware: Middleware {
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
print("1")
guard request.uri.scheme != "https" else { // 1
let response = try next.respond(to:request) // 2
print("7")
return response // 3
}
let uri = uriWithSecureScheme
print("alternate")
return Response(redirect:uri.description) // 4
}
}
struct HeadersMiddleware: Middleware {
funcrespond(torequest:Request,chainingTonext:Responder)throws->Response{
print("2")
let response=try next.respond(to:request) // 1
print("6")
response.headers["Cache-Control"] = "public, max-age=86400" // 2
// Disable the embedding of the site in an external one.
response.headers["Content-Security-Policy"] = "frame-ancestors 'none'"
response.headers["X-Frame-Options"] ="DENY"
return response// 3
}
}
struct GzipMiddleware: Middleware {
func respond(torequest: Request, chainingTo next: Responder) throws->Response {
print("3")
let response = try next.respond(to: request) // 1
print("5")
response.body = gzippedBody // 2
response.headers["Content-Encoding"] = "gzip"// 3
response.headers["Content-Length"] = gzippedBody.length
returnresponse // 4
}
}
func respond(to request: Request) throws -> Response
extension Droplet: Responder {
public func respond(to request: Request) throws -> Response {
[...]
print("0")
let mainResponder = middleware.chain(to: routerResponder) // 1
var response: Response
do {
response = try mainResponder.respond(to: request) // 2
}
catch {
return Response(status: .internalServerError, headers: [:], body: "Error message".bytes)// 3
}
print("10")
returnresponse// 4
}
}
extension Request {
public struct Handler: Responder {
public typealias Closure = (Request) throws -> Response
private let closure: Closure
public init(_c losure: @escaping Closure) {
self.closure = closure // 1
}
public func respond(to request: Request) throws -> Response {
return try closure(request) // 2
}
}
}
extension Collection where Iterator.Element == Middleware {
func chain(to responder: Responder) -> Responder {
return reversed().reduce(responder) { nextResponder, nextMiddleware in // 3
return Request.Handler { request in
return try nextMiddleware.respond(to: request, chainingTo: nextResponder) // 4
}
}
}
}
reverse ->
[Gzip, Headers, Redirect] ->
create and return a Handler, that in its closure calls Gzip's respond(to: request, chainingTo: mainResponder) ->
create and return a Handler, that in its closure calls Headers' respond(to: request, chainingTo: gzipResponder) ->
create and return a Handler, that in its closure calls Redirect's respond(to: request, chainingTo: headersResponder) ->
return the Redirect Handler
drop.get("/test", handler: { request in
print("4")
return try JSON(node: "This is a test page.")
})
create the main responder ("0") ->
RequestMiddleware ("1") ->
Other, internal middleware ->
HeadersMiddleware ("2") ->
GZipMiddleware ("3") ->
MiscMiddleware1 ->
MiscMiddleware2
get's handler ("4") ->
GZipMiddleware ("5") ->
HeadersMiddleware ("6") ->
Other, internal middleware ->
RequestMiddleware ("7") ->
response is sent to client ("10")
get("/test") ->
RequestMiddleware ("1") ->
RequestMiddleware ("alternate") ->
start over ->
RequestMiddleware ("1") ->
[continue with the rest of the secure path]
extension String: Error { } // 1
drop.get("/handle", handler: { request in
do {
let answer = try findAnswer(in: request)
returnJSON(answer) // 2
}
catch {
return JSON("Answer couldn't be computed.") // 3
}
})
drop.get("/pass-along", handler: { request in
let answer = try findAnswer(in: request) // 4
return JSON(answer) // 5
})
func findAnswer(for request: Request) throws->String {
guard let answer = request.extract("answer") as? String else {
throw "Answer parameter is not present." // 6
}
guard computingFinishedFast else {
throw "Computing took too long to finish."
}
return answer
}
enum AppError: Error {
case argumentNotPresent(name: String)
case computingTimedOut
}
drop.get("/handle", handler: { request in
do {
let answer = try findAnswer(in: request)
return JSON(answer) // 1
}
catch {
return JSON("Answer couldn't be computed.") // 2
}
})
drop.get("/pass-along", handler: { request in
let answer = try findAnswer(in: request) // 3
return JSON(answer) // 4
})
func findAnswer(for request: Request) throws -> String {
guard let answer = request.extract("answer") as? String else {
throw AppError.argumentNotPresent(name:"answer") // 5
}
guard computingFinishedFast else {
throw AppError.computingTimedOut // 6
}
return answer
}
struct ErrorHandlingMiddleware: Middleware {
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
do {
return try next.respond(to: request) // 1
}
catch AppError.argumentNotPresent(let name) { // 2
throw Abort.custom( // 3
status: .badRequest,
message: "Argument \(name) was not found." // 4
)
}
catch AppError.computingTimedOut { // 5
throw Abort.custom(
status: .requestTimeout, // 6
message: "Computing an answer has timed out."
)
}
catch { // 7
return Response( // 8
status: .serverError,
message: "Something unexpected happened."
)
}
}
}
func findMeaningOfLife(for request: Request) throws -> Int {
guard let answer = request.extract("meaningOfLife") as? Int else {
throw AppError.argumentNotPresent(name: "meaningOfLife")
}
return 42
}
// [...]
drop.middleware.append(ErrorHandlingMiddleware())
// [...]
// [...]
// drop.middleware.append(ErrorHandlingMiddleware()) -> replaced with:
drop.addConfigurable(middleware: ErrorHandlingMiddleware(), name: "error-handling")
// [...]
// production/droplet.json
{
...
"middleware": {
"server": [
...
"error-handling", // 1
...
],
"client": [
...
]
},
...
}
// staging/droplet.json
{
...
"middleware": {
"server": [
... // 2
],
"client": [
...
]
},
...
}
이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은
- 블로그 댓글
- 페이스북 페이지(@나는한다번역)
- 이메일(canapio.developer@gmail.com)
- 트위터(@canapio)
으로 보내주시면 됩니다.
'Swift와 iOS > 기술' 카테고리의 다른 글
[번역]인스트루먼트없이 누수 뷰컨트롤러 잡아내기 (363) | 2017.08.15 |
---|---|
[번역]iOS: Xcode의 메모리 그래프 디버거로 메모리 누수 식별하기 (2) | 2017.08.15 |
[번역]속성으로 스위프트 코드베이스를 최적화하기 (0) | 2017.06.18 |
[번역]주석에대하여 (0) | 2017.06.17 |
[번역]스위프트: UserDefaults 프로토콜 (0) | 2017.06.16 |
WRITTEN BY
- tucan.dev
개인 iOS 개발, tucan9389