Server Side Swift with Swag
-
Upload
jens-ravens -
Category
Software
-
view
4.561 -
download
0
Transcript of Server Side Swift with Swag
let me = Person(name: "Jens Ravens", company: "nerdgeschoss")
@JensRavens GitHub: JensRavens jensravens.com nerdgeschoss.de
Browser
http://jensravens.com
DNS Server
;; ANSWER SECTION: jensravens.com. 3600 IN A 37.120.178.83
Browser
http://jensravens.com
DNS Server
;; ANSWER SECTION: jensravens.com. 3600 IN A 37.120.178.83
37.120.178.83
Browser
http://jensravens.com
DNS Server
37.120.178.83GET / HTTP/1.1 Host: jensravens.com User-Agent: curl/7.43.0 Accept: */*
Browser
http://jensravens.com
DNS Server
37.120.178.83
Server
GET / HTTP/1.1 Host: jensravens.com User-Agent: curl/7.43.0 Accept: */*
Browser
http://jensravens.com
DNS Server
37.120.178.83
Server
Load Balancer
GET / HTTP/1.1 Host: jensravens.com User-Agent: curl/7.43.0 Accept: */*
Browser
http://jensravens.com
DNS Server
37.120.178.83
Server
Load Balancer
App App
GET / HTTP/1.1 Host: jensravens.com User-Agent: curl/7.43.0 Accept: */*
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 7897 Connection: Keep-Alive
<!DOCTYPE html> <html lang="en"> ...
Browser
DNS Server Server
Load Balancer
App App
public protocol RequestType { var context: [String:AnyObject] { get set } var method: HTTPMethod { get } var path: String { get } var params: [String:String] { get } var headers: [String:String] { get } var format: Format { get } var body: Streamable? { get } }
public protocol ResponseType { var headers: [String: HeaderType] { get } var code: StatusCode { get } var content: Streamable { get } }
public protocol RequestType { var context: [String:AnyObject] { get set } var method: HTTPMethod { get } var path: String { get } var params: [String:String] { get } var headers: [String:String] { get } var format: Format { get } var body: Streamable? { get } }
public protocol ResponseType { var headers: [String: HeaderType] { get } var code: StatusCode { get } var content: Streamable { get } }
public protocol RequestType { var context: [String:AnyObject] { get set } var method: HTTPMethod { get } var path: String { get } var params: [String:String] { get } var headers: [String:String] { get } var format: Format { get } var body: Streamable? { get } }
public protocol Streamable { var stream: Void -> NSData? { get } }
public typealias AppType = RequestType throws -> ResponseType
let myApp: AppType = { request in return Response(code: 200, headers: [:], content: "Hello World") }
public final class Router { public func route(method: HTTPMethod, path: String, app: Void -> AppType)
public func get(path: String, app: Void -> AppType)
public func app(request: RequestType) throws -> ResponseType }
public final class Router { public func route(method: HTTPMethod, path: String, app: Void -> AppType)
public func get(path: String, app: Void -> AppType)
public func app(request: RequestType) throws -> ResponseType }
let myApp: AppType = { request in return Response(code: 200, headers: [:], content: "Hello World") }
public final class Router { public func route(method: HTTPMethod, path: String, app: Void -> AppType)
public func get(path: String, app: Void -> AppType)
public func app(request: RequestType) throws -> ResponseType }
let myApp: AppType = { request in return Response(code: 200, headers: [:], content: "Hello World") }
let router = Router() router.get("home") { myApp } let routedApp = router.app
public protocol ViewType { func render() throws -> Streamable var contentType: FormatType { get } }
public struct JSONView: ViewType { public var contentType: FormatType { return Format.JSON } let contents: AnyObject public init(_ contents: AnyObject) { self.contents = contents } public func render() throws -> Streamable { return try NSJSONSerialization.dataWithJSONObject( contents, options: .PrettyPrinted) } }
public protocol ControllerType {}
extension ControllerType { func redirect(path: PathConvertible, statusCode: StatusCode = 302) -> ResponseType
func render(view view: ViewType, statusCode: StatusCode = 200) throws -> ResponseType
func render(json json: AnyObject, statusCode: StatusCode = 200) throws -> ResponseType
func render(html html: String, statusCode: StatusCode = 200) throws -> ResponseType }
struct UsersController: ControllerType { func index(request: RequestType) throws -> ResponseType { let users: [User] = …
switch request.format { case .JSON: return try render(json: users.map { $0.json }) default: return try render(view: MustacheView(name: "template", context: users)) } } }
struct UsersController: ControllerType { func index(request: RequestType) throws -> ResponseType { let users: [User] = …
switch request.format { case .JSON: return try render(json: users.map { $0.json }) default: return try render(view: MustacheView(name: "template", context: users)) } } }
let router = Router() router.get(“/users") { UsersController().index } let routedApp = router.app
public typealias MiddlewareType = AppType -> AppType
public func + (lhs: MiddlewareType, rhs: AppType) -> AppType { return lhs(rhs) }
public typealias MiddlewareType = AppType -> AppType
public func + (lhs: MiddlewareType, rhs: AppType) -> AppType { return lhs(rhs) }
let awesomeMiddleware: MiddlewareType = { app in return { request in var response = try app(request) response.content = "Overwritten by middleware" return response } }
public typealias MiddlewareType = AppType -> AppType
public func + (lhs: MiddlewareType, rhs: AppType) -> AppType { return lhs(rhs) }
let awesomeMiddleware: MiddlewareType = { app in return { request in var response = try app(request) response.content = "Overwritten by middleware" return response } }
let router = Router() router.get(“/users") { awesomeMiddleware + UsersController().index } let routedApp = router.app
class CookieStore { struct Cookie { public var name: String public var value: String public var validUntil: NSDate? } var cookies = [String:Cookie]() subscript(key: String) -> String? static func middleware(app: AppType) -> AppType }
class CookieStore { struct Cookie { public var name: String public var value: String public var validUntil: NSDate? } var cookies = [String:Cookie]() subscript(key: String) -> String? static func middleware(app: AppType) -> AppType }
let router = Router() router.get(“/users") { CookieStore().middleware + UsersController().index } let routedApp = router.app
class CookieStore { struct Cookie { public var name: String public var value: String public var validUntil: NSDate? } var cookies = [String:Cookie]() subscript(key: String) -> String? static func middleware(app: AppType) -> AppType }
let router = Router() router.get(“/users") { CookieStore().middleware + UsersController().index } let routedApp = router.app
extension RequestType { public var cookies: CookieStore! }
func login(request: RequestType) throws -> ResponseType { let secret = request.params["secret"] ?? "" request.cookies["secret"] = secret return try render(text: "Login successfull") } func secretStuff(request: RequestType) throws -> ResponseType { if request.cookies["secret"] == "superSecret" { return try render(text: "Here's the secret page") } else { return try render(text: "Permission denied!", status: 403) } }
func login(request: RequestType) throws -> ResponseType { let secret = request.params["secret"] ?? "" request.cookies["secret"] = secret return try render(text: "Login successfull") } func secretStuff(request: RequestType) throws -> ResponseType { if request.cookies["secret"] == "superSecret" { return try render(text: "Here's the secret page") } else { return try render(text: "Permission denied!", status: 403) } }
let router = Router() router.post(“/login”) { CookieStore().middleware + login } router.get(“/my-secret-page“) { CookieStore().middleware + secretStuff } let routedApp = router.app
MiddlewareCookies
Sessions
Current User
Format DetectionCustom Error Pages
HTTP Body Parser
Static File Server
Analytics
Nest Server Interface
https://github.com/nestproject/Nest
import Curassow import Inquiline
serve { request in return Response(.Ok, contentType: "text/plain", body: "Hello World") }
Epoch
https://github.com/Zewo/Epoch
struct ServerResponder: ResponderType { func respond(request: Request) -> Response { // do something based on the Request return Response(status: .OK) } }
let responder = ServerResponder() let server = Server(port: 8080, responder: responder) server.start()
Swag
https://github.com/swagproject/swag
import Foundation import Curassow import SwagNest
final class NextApp: App { override init() { super.init() register(FileServer(root: publicDir).serve) register(BodyParser.middleware) register(CookieStore.middleware) router.get(“/users") { UsersController.middleware + UsersController().index } router.get("/users/:id") { UsersController().show } } }
serve(NextApp().nest)