SlideShare ist ein Scribd-Unternehmen logo
1 von 46
Downloaden Sie, um offline zu lesen
Taking Swift to the Server
let me = Person(name: "Jens Ravens", company: "nerdgeschoss")
@JensRavens
GitHub: JensRavens
jensravens.com
nerdgeschoss.de
A short introduction to
http, tcp and ip.
Browser
http://jensravens.com
Browser
http://jensravens.com
DNS Server
Browser
http://jensravens.com
DNS Server
;; ANSWER SECTION:
jensravens.com. 3600 INA 37.120.178.83
Browser
http://jensravens.com
DNS Server
;; ANSWER SECTION:
jensravens.com. 3600 INA 37.120.178.83
37.120.178.83
Browser
http://jensravens.com
DNS Server
37.120.178.83
Browser
http://jensravens.com
DNS Server
37.120.178.83
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
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: */*
Browser
DNS Server Server
Load Balancer
App App
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 7897
Connection: Keep-Alive
<!DOCTYPE html>
Browser
DNS Server Server
Load Balancer
App App
Hey, that’s just some
plain text over tcp!
Get a Request,
give a Response
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
public typealias AppType = RequestType throws
-> ResponseType
let myApp: AppType = { request in
return Response(code: 200, headers: [:],
content: "Hello World")
}
Where to go next:
The Router
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
Making things pretty -
Rendering Views
public protocol ViewType {
func render() throws -> Streamable
var contentType: FormatType { get }
}
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
Extending the Stack -
Add some Middleware
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
Middleware
Cookies
Sessions
Current User
Format Detection
Custom Error Pages
HTTP Body Parser
Static File Server
Analytics
Mounting your App
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)
Thank you.
@JensRavens
github.com/swagproject/swag

Weitere ähnliche Inhalte

Was ist angesagt?

Parse cloud code
Parse cloud codeParse cloud code
Parse cloud code
維佋 唐
 
Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013
Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013
Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013
Aaron Parecki
 

Was ist angesagt? (20)

Intro to Parse
Intro to ParseIntro to Parse
Intro to Parse
 
What's Parse
What's ParseWhat's Parse
What's Parse
 
Parse cloud code
Parse cloud codeParse cloud code
Parse cloud code
 
第一次用Parse就深入淺出
第一次用Parse就深入淺出第一次用Parse就深入淺出
第一次用Parse就深入淺出
 
Parse Advanced
Parse AdvancedParse Advanced
Parse Advanced
 
&lt;x> Rails Web App Security Title
&lt;x> Rails Web App Security Title&lt;x> Rails Web App Security Title
&lt;x> Rails Web App Security Title
 
Android search
Android searchAndroid search
Android search
 
Working With Sharepoint 2013 Apps Development
Working With Sharepoint 2013 Apps DevelopmentWorking With Sharepoint 2013 Apps Development
Working With Sharepoint 2013 Apps Development
 
Google cloud datastore driver for Google Apps Script DB abstraction
Google cloud datastore driver for Google Apps Script DB abstractionGoogle cloud datastore driver for Google Apps Script DB abstraction
Google cloud datastore driver for Google Apps Script DB abstraction
 
 +  = ❤️ (Firebase for Apple Developers) at Swift Leeds
 +  = ❤️ (Firebase for Apple Developers) at Swift Leeds +  = ❤️ (Firebase for Apple Developers) at Swift Leeds
 +  = ❤️ (Firebase for Apple Developers) at Swift Leeds
 
Html indexed db
Html indexed dbHtml indexed db
Html indexed db
 
Introduction to SharePoint 2013 REST API
Introduction to SharePoint 2013 REST APIIntroduction to SharePoint 2013 REST API
Introduction to SharePoint 2013 REST API
 
How To Manage API Request with AXIOS on a React Native App
How To Manage API Request with AXIOS on a React Native AppHow To Manage API Request with AXIOS on a React Native App
How To Manage API Request with AXIOS on a React Native App
 
Integrate CI/CD Pipelines with Jira Software Cloud
Integrate CI/CD Pipelines with Jira Software CloudIntegrate CI/CD Pipelines with Jira Software Cloud
Integrate CI/CD Pipelines with Jira Software Cloud
 
Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...
Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...
Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...
 
Url programming
Url programmingUrl programming
Url programming
 
Firebase for Apple Developers
Firebase for Apple DevelopersFirebase for Apple Developers
Firebase for Apple Developers
 
Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4
 
Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013
Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013
Building Web Apps with the Esri-Leaflet Plugin - Dubai DevSummit 2013
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4
 

Ähnlich wie Server Side Swift with Swag

Golang slidesaudrey
Golang slidesaudreyGolang slidesaudrey
Golang slidesaudrey
Audrey Lim
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript
Qiangning Hong
 

Ähnlich wie Server Side Swift with Swag (20)

Android and REST
Android and RESTAndroid and REST
Android and REST
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Golang slidesaudrey
Golang slidesaudreyGolang slidesaudrey
Golang slidesaudrey
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript
 
Local SQLite Database with Node for beginners
Local SQLite Database with Node for beginnersLocal SQLite Database with Node for beginners
Local SQLite Database with Node for beginners
 
Server Side Swift - AppBuilders 2017
Server Side Swift - AppBuilders 2017Server Side Swift - AppBuilders 2017
Server Side Swift - AppBuilders 2017
 
Express JS
Express JSExpress JS
Express JS
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
Dart Power Tools
Dart Power ToolsDart Power Tools
Dart Power Tools
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasy
 
RESTEasy
RESTEasyRESTEasy
RESTEasy
 
Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middleware
 
Overview of RESTful web services
Overview of RESTful web servicesOverview of RESTful web services
Overview of RESTful web services
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
 
RESTful web services
RESTful web servicesRESTful web services
RESTful web services
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web Apps
 

Mehr von Jens Ravens

Hipster Oriented Programming
Hipster Oriented ProgrammingHipster Oriented Programming
Hipster Oriented Programming
Jens Ravens
 

Mehr von Jens Ravens (9)

Turning it up to 11 - Scaling Ruby on Rails to 100k rps
Turning it up to 11 - Scaling Ruby on Rails to 100k rpsTurning it up to 11 - Scaling Ruby on Rails to 100k rps
Turning it up to 11 - Scaling Ruby on Rails to 100k rps
 
Server Side Swift
Server Side SwiftServer Side Swift
Server Side Swift
 
Working with Xcode and Swift Package Manager
Working with Xcode and Swift Package ManagerWorking with Xcode and Swift Package Manager
Working with Xcode and Swift Package Manager
 
Taming Asynchronous Transforms with Interstellar
Taming Asynchronous Transforms with InterstellarTaming Asynchronous Transforms with Interstellar
Taming Asynchronous Transforms with Interstellar
 
Hipster oriented programming (Mobilization Lodz 2015)
Hipster oriented programming (Mobilization Lodz 2015)Hipster oriented programming (Mobilization Lodz 2015)
Hipster oriented programming (Mobilization Lodz 2015)
 
Hipster Oriented Programming
Hipster Oriented ProgrammingHipster Oriented Programming
Hipster Oriented Programming
 
Swift 2
Swift 2Swift 2
Swift 2
 
Functional Reactive Programming without Black Magic (UIKonf 2015)
Functional Reactive Programming without Black Magic (UIKonf 2015)Functional Reactive Programming without Black Magic (UIKonf 2015)
Functional Reactive Programming without Black Magic (UIKonf 2015)
 
Swift: Immutability and You
Swift: Immutability and YouSwift: Immutability and You
Swift: Immutability and You
 

Kürzlich hochgeladen

AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
Alluxio, Inc.
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
mbmh111980
 
JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)
Max Lee
 

Kürzlich hochgeladen (20)

Crafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationCrafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM Integration
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
 
IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024
 
CompTIA Security+ (Study Notes) for cs.pdf
CompTIA Security+ (Study Notes) for cs.pdfCompTIA Security+ (Study Notes) for cs.pdf
CompTIA Security+ (Study Notes) for cs.pdf
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf
 
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning Framework
 
AI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in Michelangelo
 
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
 
5 Reasons Driving Warehouse Management Systems Demand
5 Reasons Driving Warehouse Management Systems Demand5 Reasons Driving Warehouse Management Systems Demand
5 Reasons Driving Warehouse Management Systems Demand
 
What need to be mastered as AI-Powered Java Developers
What need to be mastered as AI-Powered Java DevelopersWhat need to be mastered as AI-Powered Java Developers
What need to be mastered as AI-Powered Java Developers
 
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product UpdatesGraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
 
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
 
APVP,apvp apvp High quality supplier safe spot transport, 98% purity
APVP,apvp apvp High quality supplier safe spot transport, 98% purityAPVP,apvp apvp High quality supplier safe spot transport, 98% purity
APVP,apvp apvp High quality supplier safe spot transport, 98% purity
 
Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024
 
The Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionThe Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion Production
 
Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024
 
JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)
 

Server Side Swift with Swag

  • 1. Taking Swift to the Server
  • 2. let me = Person(name: "Jens Ravens", company: "nerdgeschoss") @JensRavens GitHub: JensRavens jensravens.com nerdgeschoss.de
  • 3. A short introduction to http, tcp and ip.
  • 6. Browser http://jensravens.com DNS Server ;; ANSWER SECTION: jensravens.com. 3600 INA 37.120.178.83
  • 7. Browser http://jensravens.com DNS Server ;; ANSWER SECTION: jensravens.com. 3600 INA 37.120.178.83 37.120.178.83
  • 9. Browser http://jensravens.com DNS Server 37.120.178.83 GET / HTTP/1.1 Host: jensravens.com User-Agent: curl/7.43.0 Accept: */*
  • 10. 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: */*
  • 11. 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: */*
  • 12. 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: */*
  • 13. Browser DNS Server Server Load Balancer App App
  • 14. HTTP/1.1 200 OK Content-Type: text/html Content-Length: 7897 Connection: Keep-Alive <!DOCTYPE html> Browser DNS Server Server Load Balancer App App
  • 15. Hey, that’s just some plain text over tcp!
  • 16. Get a Request, give a Response
  • 17. 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 } }
  • 18. 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 } }
  • 19. 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 } }
  • 20. public typealias AppType = RequestType throws -> ResponseType
  • 21. public typealias AppType = RequestType throws -> ResponseType let myApp: AppType = { request in return Response(code: 200, headers: [:], content: "Hello World") }
  • 22. Where to go next: The Router
  • 23. 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 }
  • 24. 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") }
  • 25. 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
  • 26. Making things pretty - Rendering Views
  • 27. public protocol ViewType { func render() throws -> Streamable var contentType: FormatType { get } }
  • 28. 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) } }
  • 29. 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 }
  • 30. 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)) } } }
  • 31. 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
  • 32. Extending the Stack - Add some Middleware
  • 33. public typealias MiddlewareType = AppType -> AppType public func + (lhs: MiddlewareType, rhs: AppType) -> AppType { return lhs(rhs) }
  • 34. 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 } }
  • 35. 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
  • 36. 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 }
  • 37. 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
  • 38. 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! }
  • 39. 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) } }
  • 40. 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
  • 41. Middleware Cookies Sessions Current User Format Detection Custom Error Pages HTTP Body Parser Static File Server Analytics
  • 43. Nest Server Interface https://github.com/nestproject/Nest import Curassow import Inquiline serve { request in return Response(.Ok, contentType: "text/plain", body: "Hello World") }
  • 44. 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()
  • 45. 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)