SlideShare a Scribd company logo
1 of 64
Download to read offline
Vapor 

(Server-side Swift)
Swift
• Multi-paradigm

• Statically typed

• Fast 

(https://benchmarksgame-team.pages.debian.net/benchmarksgame/faster/swift.html)

• Safe

• Easy to understand

• Open Source

• Community
Where it all started
Swift NIO
SwiftNIO is a cross-platform asynchronous event-driven network application
framework for rapid development of maintainable high performance protocol
servers & clients.
https://www.youtube.com/watch?v=QJ3WG9kRLMo
How to start
brew install vapor/tap/vapor apt-get install vapor -y
Check compatibility
eval "$(curl -sL check.vapor.sh)
And the output should look something like this

⚠ Xcode 10 support hasn't been tested yet.
ℹ Xcode 10 should be compatible with Vapor 2.
ℹ Xcode 10 should be compatible with Vapor 3.
⚠ Swift 4.2 support hasn't been tested yet.
ℹ Swift 4.2 should be compatible with Vapor 2.
ℹ Swift 4.2 should be compatible with Vapor 3.
First App
vapor new TestApp
cd TestApp
vapor build
vapor run
http://localhost:8080/hello/
Xcode project
No Xcode project 😱
Generate Xcode project
vapor xcode -y
What Xcode gives you
• All That fun stuff that it already has

• Debugging
Let us dive inside vapor
magic
Swift Package Manager
(SPM)
Routes
//routes.swift
import Vapor
public func routes(_ router: Router) throws {
router.get { req in
return "It works!"
}
router.get("hello") { req in
return "Hello, world!"
}
}
• http://localhost:8080/

• http://localhost:8080/hello/
Routes with parameters
router.get("hello", String.parameter) { req -> String in
let name = try req.parameters.next(String.self)
return "Hello, (name)!"
}
• http://localhost:8080/hello/Anna/
Route grouping
router.group("hello") { (router) in
router.get { req in
return "Hello, world!"
}
router.get(String.parameter) { req -> String in
let name = try req.parameters.next(String.self)
return "Hello, (name)!"
}
}
Route Collection
Conformance to RouteCollection
// HelloRoutesCollection.swift
final class HelloRoutesCollection: RouteCollection {
func boot(router: Router) throws {
router.group("hello") { (router) in
router.get { req in
return "Hello, world!"
}
router.get(String.parameter) { req -> String in
let name = try req.parameters.next(String.self)
return "Hello, (name)!"
}
}
}
}
//routes.swift
try router.register(collection: HelloRoutesCollection())
Clean this with Controller.
// HelloController.swift
final class HelloController {
func hello(_ req: Request) -> String {
return "Hello, world!"
}
func personalHello(_ req: Request) throws -> String {
let name = try req.parameters.next(String.self)
return "Hello, (name)!"
}
}
// HelloRoutesCollection.swift
router.group("hello") { (router) in
router.get("", use: controller.hello)
router.get(String.parameter, use:
controller.personalHello)
}
Current Route
routes.swift HelloRoutesCollection HelloController
Accepting data
// HelloMessage.swift
struct HelloMessage: Content {
let message: String
}
// HelloController.swift
func postHelloMessage(_ req: Request, _ message: HelloMessage) throws -> String {
return message.message + "n"
}
// HelloRoutesCollection.swift
router.post(HelloMessage.self, at: "", use: controller.postHelloMessage)
curl -d '{"message": "hello vapor"}' --header "content-type: application/json" http://localhost:8080/hello/
Returning JSON
func postHelloMessage(_ req: Request, _ message: HelloMessage) throws -> HelloMessage {
return HelloMessage(message: "Hello you”)
}
{
"message": "Hello you"
}
Troubleshooting
• `vapor xcode -y` - To fix configuration
errors or missing files in project
• `vapor update` - updating dependencies

• `rm -rf .build` - this will remove all build
artifacts
Async in Vapor
Async code in Vapor

Concept of Future
func getHelloMessages(_ req: Request) throws -> [HelloMessage] {
func getHelloMessages(_ req: Request) throws -> Future<[HelloMessage]> {
func imaginary(_ req: Request) throws -> Future<[Story]> {
let client = try req.make(Client.self)
let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/"
return client.send(.GET, to: url)
.flatMap(to: [Story].self, { (response) -> EventLoopFuture<[Story]> in
return try response.content.decode([Story].self)
})
}
flatMap()
• Use it when Promise closure returns a Future

• When you want to unpack value and work with raw data
map()
• When Promise returns anything else than Future

• To map result from long operation in Future
transform
• When you don’t care about result data only want to know
about result status (success/failure)
func imaginary(_ req: Request) throws -> Future<HTTPStatus> {
let client = try req.make(Client.self)
let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/"
return client.send(.GET, to: url).transform(to: HTTPStatus.noContent)
}
Future - multiple features
• To wait for multiple Futures to end
func imaginary(_ req: Request) throws -> Future<HTTPStatus> {
let client = try req.make(Client.self)
let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/"
return map(to: HTTPStatus.self,
try req.content.decode(Story.self),
client.send(.GET, to: url)) { (parameter, response) -> (HTTPStatus) in
return HTTPStatus.noContent
}
}
Manual Future
func imaginary(_ req: Request) throws -> Future<HTTPStatus> {
return req.future(HTTPStatus.noContent)
}
Error handling
• do{…}.catch{…}
• catchMap{…}
• catchFlatMap{…}
Chaining futures
• flatMap and map can be chained
func imaginary(_ req: Request) throws -> Future<HTTPStatus> {
let client = try req.make(Client.self)
let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/"
return client.send(.GET, to: url)
.flatMap(to: [Story].self, { (response) -> EventLoopFuture<[Story]> in
return try response.content.decode([Story].self)
}).flatMap(to: HTTPStatus.self, { (_) -> EventLoopFuture<HTTPStatus> in
return req.future(.ok)
})
}
always
func imaginary(_ req: Request) throws -> Future<HTTPStatus> {
let _ = try req.content.decode(Story.self).always {
print("This code will execute always")
}
return req.future(.ok)
}
When you need something to execute always, no matter the
result
wait
• Mostly not usable in code 💥
func imaginary(_ req: Request) throws -> Future<HTTPStatus> {
let client = try req.make(Client.self)
let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/"
let stories = try client.send(.GET, to: url).flatMap(to: [Story].self)
{ (response) -> EventLoopFuture<[Story]> in
return try response.content.decode([Story].self)
}.wait()
return req.future(.ok)
}
Fluent
• Mapping between objects with CRUD support

• Querying data

• Relationships

• Session live cache

• Custom queries

• Transaction support

• Migrations

• Numerous database types support
Supported types
How to add persistence
//configure.swift
let sqlite = try SQLiteDatabase(storage: .memory)
var databases = DatabasesConfig()
databases.add(database: sqlite, as: .sqlite)
services.register(databases)
Defining your first model
import FluentSQLite
struct HelloMessage: Content {
var id: Int?
let message: String
}
extension HelloMessage: Model {
typealias Database = SQLiteDatabase
typealias ID = Int
static var idKey: IDKey = HelloMessage.id
}
Is it really all?
//HelloMessage.swift
extension HelloMessage: Migration {}
//configure.swift
var migrations = MigrationConfig()
migrations.add(model: HelloMessage.self, database: .sqlite)
services.register(migrations)
Migrations
extension HelloMessage: Migration {
static func prepare(on connection: SQLiteConnection) -> Future<Void> {
}
}
What can we do now?
func messeges(_ req: Request) throws -> Future<[HelloMessage]> {
return HelloMessage.query(on: req).all()
}
func newMessage(_ req: Request) throws -> Future<HelloMessage> {
let message = try req.content.decode(HelloMessage.self)
return message.save(on: req)
}
func editMessage(_ req: Request, _ message: HelloMessage) throws -> Future<HelloMessage> {
return try req.content.decode(HelloMessage.self).flatMap({ (newMessage) ->
EventLoopFuture<HelloMessage> in
let edited = HelloMessage(id: message.id, message: newMessage.message)
return edited.save(on: req)
})
}
func delete(_ req: Request) throws -> Future<HTTPStatus> {
return try req.parameters.next(HelloMessage.self)
.flatMap({ (message) -> EventLoopFuture<HTTPStatus> in
return message.delete(on: req).transform(to: .ok)
})
}
Hosting
https://www.heroku.com/ https://vapor.cloud/ https://www.digitalocean.com/
Vapor cloud
• Create an account (https://dashboard.vapor.cloud/)

• Prepare deploy cloud.yml
type: "vapor"
swift_version: "4.1.0"
run_parameters: "serve --port 8080 --hostname 0.0.0.0"
https://docs.vapor.cloud/configuration/general/
Vapor CLI Tool
• vapor cloud login
• vapor cloud deploy
• Configure repo (ssh/https)
• Create Project
• Select Organisation
• Name the project
• Provide application Slug (https://<slug>.vapor.cloud)
• Setup Environment
• DB selection
• Build type (incremental, update, clean)
Leaf Templates
// Package.swift
.package(url: "https://github.com/vapor/leaf.git", from: “3.0.0-rc")
.target(name: "App", dependencies: ["FluentSQLite", "Vapor", “Leaf”])
//configure.swift
try services.register(LeafProvider())
config.prefer(LeafRenderer.self, for: ViewRenderer.self)
vapor update
Updating [Done]
Changes to dependencies usually require Xcode to be regenerated.
Would you like to regenerate your xcode project now?
y/n> y
Generating Xcode Project [Done]
Select the `Run` scheme to run.
Open Xcode project?
y/n> y
Opening Xcode project...
Rendering page
• Create index.leaf view in Resources/Views directory
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello Leaf</title>
</head>
<body>
<h1>Hello Leaf</h1>
</body>
</html>
• Add new route for index and inside render index view
router.get("index") { (req) -> Future<View> in
return try req.view().render("index")
}
Injecting context
struct IndexContext: Encodable {
let title: String
}
<title>#(title)</title>
router.get("index") { (req) -> Future<View> in
let context = IndexContext(title: "Home Sweet Home")
return try req.view().render("index", context)
}
More about Leaf
• Conditions with #if {} else if {} else {}…

• Loops #for…in…{}

• Content embedding with #embed #set

• Custom tag operations like 

• Date formatting with #date

• Text formatting with #capitalize and #lowercase

• Many more
Authentication
• Base Authentication

• Token Authentication

• Session

• OAuth 2.0
Passwords
import Crypto
self.password = try BCrypt.hash(password)
let password = User.basicAuthMiddleware(using: BCryptDigest())
Adding Auth
// Package.swift
.package(url: "https://github.com/vapor/auth.git",from: “2.0.0-rc")
.target(name: "App", dependencies: ["FluentSQLite", "Vapor", "Leaf", "Authentication"]),
vapor update
Auth 

Conformance
extension User: BasicAuthenticatable {
static var usernameKey: IDKey = User.name
static var passwordKey: IDKey = User.password
}
extension User: PasswordAuthenticatable {
static var usernameKey: IDKey = User.name
static var passwordKey: IDKey = User.password
}
extension User: TokenAuthenticatable {
typealias TokenType = UserToken
}
struct UserToken: Model {
var id: Int?
var string: String
var userID: User.ID
var user: Parent<UserToken, User> {
return parent(.userID)
}
}
Make Auth Work
// configure.swift
try services.register(AuthenticationProvider())
let basicMiddleware = User.basicAuthMiddleware(using: BCryptDigest())
let guardAuthMiddleware = User.guardAuthMiddleware()
let protectedRouter = router.grouped([basicMiddleware, guardAuthMiddleware])
protectedRouter.get { req in
return "It works only in auth"
}
Session
extension User: PasswordAuthenticatable {}
extension User: SessionAuthenticatable {}
middlewares.use(SessionsMiddleware.self)
config.prefer(MemoryKeyedCache.self, for: KeyedCache.self)
let authSessionRoutes = router.grouped(User.authSessionsMiddleware())
OAuth 2.0
• Imperial (https://github.com/vapor-community/
Imperial.git)

• Create and setup project in Google console

• Create dedicated RouteCollection controller to handle
Google login

• Add env variables with Google client id and secret
Testing
.testTarget(name: "AppTests", dependencies: ["App"])
Change project Scheme for Testing
final class AppTests: XCTestCase {
func testNothing() throws {
// add your tests here
XCTAssert(true)
}
static let allTests = [
("testNothing", testNothing)
]
}
App in tests
override func setUp() {
var config = Config.default()
var services = Services.default()
var env = Environment.testing
try! App.configure(&config, &env, &services)
app = try! Application(config: config,
environment: env,
services: services)
}
Endpoint test
func testHelloMessage() throws {
let request = HTTPRequest(method: .GET,
url: "/hello")
let wrapper = Request(http: request, using: app)
let responder = try! app.make(Responder.self)
let response = try! responder.respond(to: wrapper).wait()
let message = String(data: response.http.body.data!, encoding: .utf8)
XCTAssertEqual(message, "Hello, world!", "Wrong response from /hello")
}
Cache
• In Memory Cache

• Database Cache

• Redis
Middleware
• ErrorMiddleware
• FileMiddleware
func respond(to request: Request, chainingTo next: Responder) throws -> Future<Response>
websockets
let ws = NIOWebSocketServer.default()
ws.get("echo") { (ws, req) in
ws.onText({ (ws, str) in
ws.send(str)
})
}
Resources
• https://docs.vapor.codes/3.0/
Other

Options
https://www.kitura.io/ https://www.perfect.org/
Questions?
Thanks
https://riamf.github.io/

@riamf1

https://github.com/riamf

More Related Content

What's hot

Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAnkit Agarwal
 
Roll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and LuaRoll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and LuaJon Moore
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUNUsing ngx_lua in UPYUN
Using ngx_lua in UPYUNCong Zhang
 
Lua tech talk
Lua tech talkLua tech talk
Lua tech talkLocaweb
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to NodejsGabriele Lana
 
Bootstrapping multidc observability stack
Bootstrapping multidc observability stackBootstrapping multidc observability stack
Bootstrapping multidc observability stackBram Vogelaar
 
Node.js streaming csv downloads proxy
Node.js streaming csv downloads proxyNode.js streaming csv downloads proxy
Node.js streaming csv downloads proxyIsmael Celis
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slidesharetomcopeland
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)Domenic Denicola
 
Devinsampa nginx-scripting
Devinsampa nginx-scriptingDevinsampa nginx-scripting
Devinsampa nginx-scriptingTony Fabeen
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleVladimir Kostyukov
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012 Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012 Tom Croucher
 
Using ngx_lua in UPYUN 2
Using ngx_lua in UPYUN 2Using ngx_lua in UPYUN 2
Using ngx_lua in UPYUN 2Cong Zhang
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeKAI CHU CHUNG
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsMongoDB
 
$q and Promises in AngularJS
$q and Promises in AngularJS $q and Promises in AngularJS
$q and Promises in AngularJS a_sharif
 

What's hot (20)

Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
 
From Node to Go
From Node to GoFrom Node to Go
From Node to Go
 
Roll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and LuaRoll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and Lua
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUNUsing ngx_lua in UPYUN
Using ngx_lua in UPYUN
 
Lua tech talk
Lua tech talkLua tech talk
Lua tech talk
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to Nodejs
 
Clojure@Nuday
Clojure@NudayClojure@Nuday
Clojure@Nuday
 
Bootstrapping multidc observability stack
Bootstrapping multidc observability stackBootstrapping multidc observability stack
Bootstrapping multidc observability stack
 
Node.js streaming csv downloads proxy
Node.js streaming csv downloads proxyNode.js streaming csv downloads proxy
Node.js streaming csv downloads proxy
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)
 
Devinsampa nginx-scripting
Devinsampa nginx-scriptingDevinsampa nginx-scripting
Devinsampa nginx-scripting
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with Finagle
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012 Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012
 
Using ngx_lua in UPYUN 2
Using ngx_lua in UPYUN 2Using ngx_lua in UPYUN 2
Using ngx_lua in UPYUN 2
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.js
 
Plack - LPW 2009
Plack - LPW 2009Plack - LPW 2009
Plack - LPW 2009
 
$q and Promises in AngularJS
$q and Promises in AngularJS $q and Promises in AngularJS
$q and Promises in AngularJS
 

Similar to Vapor Server-side Swift Guide

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Sharding and Load Balancing in Scala - Twitter's Finagle
Sharding and Load Balancing in Scala - Twitter's FinagleSharding and Load Balancing in Scala - Twitter's Finagle
Sharding and Load Balancing in Scala - Twitter's FinagleGeoff Ballinger
 
Clojure and the Web
Clojure and the WebClojure and the Web
Clojure and the Webnickmbailey
 
Introduction to Vert.x
Introduction to Vert.xIntroduction to Vert.x
Introduction to Vert.xYiguang Hu
 
Spring Web Services: SOAP vs. REST
Spring Web Services: SOAP vs. RESTSpring Web Services: SOAP vs. REST
Spring Web Services: SOAP vs. RESTSam Brannen
 
Node.js System: The Approach
Node.js System: The ApproachNode.js System: The Approach
Node.js System: The ApproachHaci Murat Yaman
 
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 middlewareAlona Mekhovova
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript名辰 洪
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...Tom Croucher
 
GWT Web Socket and data serialization
GWT Web Socket and data serializationGWT Web Socket and data serialization
GWT Web Socket and data serializationGWTcon
 
HTML5: huh, what is it good for?
HTML5: huh, what is it good for?HTML5: huh, what is it good for?
HTML5: huh, what is it good for?Remy Sharp
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomyDongmin Yu
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparisonHiroshi Nakamura
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the wayOleg Podsechin
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...Tom Croucher
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortalJennifer Bourey
 

Similar to Vapor Server-side Swift Guide (20)

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Sharding and Load Balancing in Scala - Twitter's Finagle
Sharding and Load Balancing in Scala - Twitter's FinagleSharding and Load Balancing in Scala - Twitter's Finagle
Sharding and Load Balancing in Scala - Twitter's Finagle
 
Clojure and the Web
Clojure and the WebClojure and the Web
Clojure and the Web
 
Introduction to Vert.x
Introduction to Vert.xIntroduction to Vert.x
Introduction to Vert.x
 
Spring Web Services: SOAP vs. REST
Spring Web Services: SOAP vs. RESTSpring Web Services: SOAP vs. REST
Spring Web Services: SOAP vs. REST
 
Node.js System: The Approach
Node.js System: The ApproachNode.js System: The Approach
Node.js System: The Approach
 
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
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
5.node js
5.node js5.node js
5.node js
 
GWT Web Socket and data serialization
GWT Web Socket and data serializationGWT Web Socket and data serialization
GWT Web Socket and data serialization
 
HTML5: huh, what is it good for?
HTML5: huh, what is it good for?HTML5: huh, what is it good for?
HTML5: huh, what is it good for?
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 

Recently uploaded

Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...Call Girls in Nagpur High Profile
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Bookingdharasingh5698
 
MANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTING
MANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTINGMANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTING
MANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTINGSIVASHANKAR N
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINESIVASHANKAR N
 
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...ranjana rawat
 
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...Call Girls in Nagpur High Profile
 
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptxBSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptxfenichawla
 
Introduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptxIntroduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptxupamatechverse
 
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
Glass Ceramics: Processing and Properties
Glass Ceramics: Processing and PropertiesGlass Ceramics: Processing and Properties
Glass Ceramics: Processing and PropertiesPrabhanshu Chaturvedi
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performancesivaprakash250
 
AKTU Computer Networks notes --- Unit 3.pdf
AKTU Computer Networks notes ---  Unit 3.pdfAKTU Computer Networks notes ---  Unit 3.pdf
AKTU Computer Networks notes --- Unit 3.pdfankushspencer015
 
High Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur Escortsranjana rawat
 
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLSMANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLSSIVASHANKAR N
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlysanyuktamishra911
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxpranjaldaimarysona
 

Recently uploaded (20)

Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
 
MANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTING
MANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTINGMANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTING
MANUFACTURING PROCESS-II UNIT-1 THEORY OF METAL CUTTING
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
 
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
 
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
 
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptxBSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
 
Introduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptxIntroduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptx
 
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
Roadmap to Membership of RICS - Pathways and Routes
Roadmap to Membership of RICS - Pathways and RoutesRoadmap to Membership of RICS - Pathways and Routes
Roadmap to Membership of RICS - Pathways and Routes
 
Glass Ceramics: Processing and Properties
Glass Ceramics: Processing and PropertiesGlass Ceramics: Processing and Properties
Glass Ceramics: Processing and Properties
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
 
DJARUM4D - SLOT GACOR ONLINE | SLOT DEMO ONLINE
DJARUM4D - SLOT GACOR ONLINE | SLOT DEMO ONLINEDJARUM4D - SLOT GACOR ONLINE | SLOT DEMO ONLINE
DJARUM4D - SLOT GACOR ONLINE | SLOT DEMO ONLINE
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performance
 
AKTU Computer Networks notes --- Unit 3.pdf
AKTU Computer Networks notes ---  Unit 3.pdfAKTU Computer Networks notes ---  Unit 3.pdf
AKTU Computer Networks notes --- Unit 3.pdf
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
High Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Isha Call 7001035870 Meet With Nagpur Escorts
 
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLSMANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghly
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptx
 

Vapor Server-side Swift Guide

  • 1.
  • 3. Swift • Multi-paradigm • Statically typed • Fast 
 (https://benchmarksgame-team.pages.debian.net/benchmarksgame/faster/swift.html) • Safe • Easy to understand • Open Source • Community
  • 4. Where it all started
  • 5. Swift NIO SwiftNIO is a cross-platform asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. https://www.youtube.com/watch?v=QJ3WG9kRLMo
  • 6. How to start brew install vapor/tap/vapor apt-get install vapor -y
  • 7. Check compatibility eval "$(curl -sL check.vapor.sh) And the output should look something like this ⚠ Xcode 10 support hasn't been tested yet. ℹ Xcode 10 should be compatible with Vapor 2. ℹ Xcode 10 should be compatible with Vapor 3. ⚠ Swift 4.2 support hasn't been tested yet. ℹ Swift 4.2 should be compatible with Vapor 2. ℹ Swift 4.2 should be compatible with Vapor 3.
  • 8. First App vapor new TestApp cd TestApp vapor build vapor run http://localhost:8080/hello/
  • 9. Xcode project No Xcode project 😱
  • 11. What Xcode gives you • All That fun stuff that it already has • Debugging
  • 12. Let us dive inside vapor magic
  • 14. Routes //routes.swift import Vapor public func routes(_ router: Router) throws { router.get { req in return "It works!" } router.get("hello") { req in return "Hello, world!" } } • http://localhost:8080/ • http://localhost:8080/hello/
  • 15. Routes with parameters router.get("hello", String.parameter) { req -> String in let name = try req.parameters.next(String.self) return "Hello, (name)!" } • http://localhost:8080/hello/Anna/
  • 16. Route grouping router.group("hello") { (router) in router.get { req in return "Hello, world!" } router.get(String.parameter) { req -> String in let name = try req.parameters.next(String.self) return "Hello, (name)!" } }
  • 17. Route Collection Conformance to RouteCollection // HelloRoutesCollection.swift final class HelloRoutesCollection: RouteCollection { func boot(router: Router) throws { router.group("hello") { (router) in router.get { req in return "Hello, world!" } router.get(String.parameter) { req -> String in let name = try req.parameters.next(String.self) return "Hello, (name)!" } } } } //routes.swift try router.register(collection: HelloRoutesCollection())
  • 18. Clean this with Controller. // HelloController.swift final class HelloController { func hello(_ req: Request) -> String { return "Hello, world!" } func personalHello(_ req: Request) throws -> String { let name = try req.parameters.next(String.self) return "Hello, (name)!" } } // HelloRoutesCollection.swift router.group("hello") { (router) in router.get("", use: controller.hello) router.get(String.parameter, use: controller.personalHello) }
  • 20. Accepting data // HelloMessage.swift struct HelloMessage: Content { let message: String } // HelloController.swift func postHelloMessage(_ req: Request, _ message: HelloMessage) throws -> String { return message.message + "n" } // HelloRoutesCollection.swift router.post(HelloMessage.self, at: "", use: controller.postHelloMessage) curl -d '{"message": "hello vapor"}' --header "content-type: application/json" http://localhost:8080/hello/
  • 21. Returning JSON func postHelloMessage(_ req: Request, _ message: HelloMessage) throws -> HelloMessage { return HelloMessage(message: "Hello you”) } { "message": "Hello you" }
  • 22. Troubleshooting • `vapor xcode -y` - To fix configuration errors or missing files in project • `vapor update` - updating dependencies • `rm -rf .build` - this will remove all build artifacts
  • 24. Async code in Vapor Concept of Future func getHelloMessages(_ req: Request) throws -> [HelloMessage] { func getHelloMessages(_ req: Request) throws -> Future<[HelloMessage]> { func imaginary(_ req: Request) throws -> Future<[Story]> { let client = try req.make(Client.self) let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/" return client.send(.GET, to: url) .flatMap(to: [Story].self, { (response) -> EventLoopFuture<[Story]> in return try response.content.decode([Story].self) }) }
  • 25. flatMap() • Use it when Promise closure returns a Future • When you want to unpack value and work with raw data
  • 26. map() • When Promise returns anything else than Future • To map result from long operation in Future
  • 27. transform • When you don’t care about result data only want to know about result status (success/failure) func imaginary(_ req: Request) throws -> Future<HTTPStatus> { let client = try req.make(Client.self) let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/" return client.send(.GET, to: url).transform(to: HTTPStatus.noContent) }
  • 28. Future - multiple features • To wait for multiple Futures to end func imaginary(_ req: Request) throws -> Future<HTTPStatus> { let client = try req.make(Client.self) let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/" return map(to: HTTPStatus.self, try req.content.decode(Story.self), client.send(.GET, to: url)) { (parameter, response) -> (HTTPStatus) in return HTTPStatus.noContent } }
  • 29. Manual Future func imaginary(_ req: Request) throws -> Future<HTTPStatus> { return req.future(HTTPStatus.noContent) }
  • 30. Error handling • do{…}.catch{…} • catchMap{…} • catchFlatMap{…}
  • 31. Chaining futures • flatMap and map can be chained func imaginary(_ req: Request) throws -> Future<HTTPStatus> { let client = try req.make(Client.self) let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/" return client.send(.GET, to: url) .flatMap(to: [Story].self, { (response) -> EventLoopFuture<[Story]> in return try response.content.decode([Story].self) }).flatMap(to: HTTPStatus.self, { (_) -> EventLoopFuture<HTTPStatus> in return req.future(.ok) }) }
  • 32. always func imaginary(_ req: Request) throws -> Future<HTTPStatus> { let _ = try req.content.decode(Story.self).always { print("This code will execute always") } return req.future(.ok) } When you need something to execute always, no matter the result
  • 33. wait • Mostly not usable in code 💥 func imaginary(_ req: Request) throws -> Future<HTTPStatus> { let client = try req.make(Client.self) let url = "https://stories-fetcher.herokuapp.com/hnproxy/topStories/" let stories = try client.send(.GET, to: url).flatMap(to: [Story].self) { (response) -> EventLoopFuture<[Story]> in return try response.content.decode([Story].self) }.wait() return req.future(.ok) }
  • 34. Fluent • Mapping between objects with CRUD support • Querying data • Relationships • Session live cache • Custom queries • Transaction support • Migrations • Numerous database types support
  • 36. How to add persistence //configure.swift let sqlite = try SQLiteDatabase(storage: .memory) var databases = DatabasesConfig() databases.add(database: sqlite, as: .sqlite) services.register(databases)
  • 37. Defining your first model import FluentSQLite struct HelloMessage: Content { var id: Int? let message: String } extension HelloMessage: Model { typealias Database = SQLiteDatabase typealias ID = Int static var idKey: IDKey = HelloMessage.id }
  • 38. Is it really all? //HelloMessage.swift extension HelloMessage: Migration {} //configure.swift var migrations = MigrationConfig() migrations.add(model: HelloMessage.self, database: .sqlite) services.register(migrations)
  • 39. Migrations extension HelloMessage: Migration { static func prepare(on connection: SQLiteConnection) -> Future<Void> { } }
  • 40. What can we do now? func messeges(_ req: Request) throws -> Future<[HelloMessage]> { return HelloMessage.query(on: req).all() } func newMessage(_ req: Request) throws -> Future<HelloMessage> { let message = try req.content.decode(HelloMessage.self) return message.save(on: req) } func editMessage(_ req: Request, _ message: HelloMessage) throws -> Future<HelloMessage> { return try req.content.decode(HelloMessage.self).flatMap({ (newMessage) -> EventLoopFuture<HelloMessage> in let edited = HelloMessage(id: message.id, message: newMessage.message) return edited.save(on: req) }) } func delete(_ req: Request) throws -> Future<HTTPStatus> { return try req.parameters.next(HelloMessage.self) .flatMap({ (message) -> EventLoopFuture<HTTPStatus> in return message.delete(on: req).transform(to: .ok) }) }
  • 42. Vapor cloud • Create an account (https://dashboard.vapor.cloud/) • Prepare deploy cloud.yml type: "vapor" swift_version: "4.1.0" run_parameters: "serve --port 8080 --hostname 0.0.0.0" https://docs.vapor.cloud/configuration/general/
  • 43. Vapor CLI Tool • vapor cloud login • vapor cloud deploy • Configure repo (ssh/https) • Create Project • Select Organisation • Name the project • Provide application Slug (https://<slug>.vapor.cloud) • Setup Environment • DB selection • Build type (incremental, update, clean)
  • 44. Leaf Templates // Package.swift .package(url: "https://github.com/vapor/leaf.git", from: “3.0.0-rc") .target(name: "App", dependencies: ["FluentSQLite", "Vapor", “Leaf”]) //configure.swift try services.register(LeafProvider()) config.prefer(LeafRenderer.self, for: ViewRenderer.self) vapor update Updating [Done] Changes to dependencies usually require Xcode to be regenerated. Would you like to regenerate your xcode project now? y/n> y Generating Xcode Project [Done] Select the `Run` scheme to run. Open Xcode project? y/n> y Opening Xcode project...
  • 45. Rendering page • Create index.leaf view in Resources/Views directory <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Hello Leaf</title> </head> <body> <h1>Hello Leaf</h1> </body> </html> • Add new route for index and inside render index view router.get("index") { (req) -> Future<View> in return try req.view().render("index") }
  • 46. Injecting context struct IndexContext: Encodable { let title: String } <title>#(title)</title> router.get("index") { (req) -> Future<View> in let context = IndexContext(title: "Home Sweet Home") return try req.view().render("index", context) }
  • 47. More about Leaf • Conditions with #if {} else if {} else {}… • Loops #for…in…{} • Content embedding with #embed #set • Custom tag operations like • Date formatting with #date • Text formatting with #capitalize and #lowercase • Many more
  • 48. Authentication • Base Authentication • Token Authentication • Session • OAuth 2.0
  • 49. Passwords import Crypto self.password = try BCrypt.hash(password) let password = User.basicAuthMiddleware(using: BCryptDigest())
  • 50. Adding Auth // Package.swift .package(url: "https://github.com/vapor/auth.git",from: “2.0.0-rc") .target(name: "App", dependencies: ["FluentSQLite", "Vapor", "Leaf", "Authentication"]), vapor update
  • 51. Auth Conformance extension User: BasicAuthenticatable { static var usernameKey: IDKey = User.name static var passwordKey: IDKey = User.password } extension User: PasswordAuthenticatable { static var usernameKey: IDKey = User.name static var passwordKey: IDKey = User.password } extension User: TokenAuthenticatable { typealias TokenType = UserToken } struct UserToken: Model { var id: Int? var string: String var userID: User.ID var user: Parent<UserToken, User> { return parent(.userID) } }
  • 52. Make Auth Work // configure.swift try services.register(AuthenticationProvider()) let basicMiddleware = User.basicAuthMiddleware(using: BCryptDigest()) let guardAuthMiddleware = User.guardAuthMiddleware() let protectedRouter = router.grouped([basicMiddleware, guardAuthMiddleware]) protectedRouter.get { req in return "It works only in auth" }
  • 53. Session extension User: PasswordAuthenticatable {} extension User: SessionAuthenticatable {} middlewares.use(SessionsMiddleware.self) config.prefer(MemoryKeyedCache.self, for: KeyedCache.self) let authSessionRoutes = router.grouped(User.authSessionsMiddleware())
  • 54. OAuth 2.0 • Imperial (https://github.com/vapor-community/ Imperial.git) • Create and setup project in Google console • Create dedicated RouteCollection controller to handle Google login • Add env variables with Google client id and secret
  • 55. Testing .testTarget(name: "AppTests", dependencies: ["App"]) Change project Scheme for Testing final class AppTests: XCTestCase { func testNothing() throws { // add your tests here XCTAssert(true) } static let allTests = [ ("testNothing", testNothing) ] }
  • 56. App in tests override func setUp() { var config = Config.default() var services = Services.default() var env = Environment.testing try! App.configure(&config, &env, &services) app = try! Application(config: config, environment: env, services: services) }
  • 57. Endpoint test func testHelloMessage() throws { let request = HTTPRequest(method: .GET, url: "/hello") let wrapper = Request(http: request, using: app) let responder = try! app.make(Responder.self) let response = try! responder.respond(to: wrapper).wait() let message = String(data: response.http.body.data!, encoding: .utf8) XCTAssertEqual(message, "Hello, world!", "Wrong response from /hello") }
  • 58. Cache • In Memory Cache • Database Cache • Redis
  • 59. Middleware • ErrorMiddleware • FileMiddleware func respond(to request: Request, chainingTo next: Responder) throws -> Future<Response>
  • 60. websockets let ws = NIOWebSocketServer.default() ws.get("echo") { (ws, req) in ws.onText({ (ws, str) in ws.send(str) }) }