SlideShare a Scribd company logo
TodoList
Tutorial
Creating a TodoList
→ Creating a project
→ Add dependencies
→ Simple Routing
→ Error Handling
→ Promises
→ Testing
Create a Project
mkdir TodoList
cd TodoList
swift package init
swift package generate-xcodeproj
Add Dependencies
import PackageDescription
let package = Package(
name: "MyTodoList",
dependencies: [
.Package(url: "https://github.com/IBM-Swift/Kitura", majorVersion: 0, minor: 32),
.Package(url: "https://github.com/IBM-Swift/HeliumLogger", majorVersion: 0, minor: 17)
]
)
Simple Route
let router = Router()
router.get("/") { request, response, next in
response.status(.OK).send("Hello World!")
}
Simple Server
Kitura.addHTTPServer(onPort: 8090, with: todoListController.router)
Kitura.run()
Simple Logger
import HeliumLogger
HeliumLogger.use()
Log.info("Hello world!")
Using multiple targets
targets: [
Target(name: "Server", dependencies: [.Target(name: "TodoList")]),
Target(name: "TodoList")
],
Separation project to:
→ Sources/TodoList/TodoList.swift
→ Sources/Server/main.swift
Create a Controller
public final class TodoListController {
public let router = Router()
public init() {
router.get("/v1/tasks", handler: handleGetTasks)
router.post("/v1/tasks", handler: handlerAddTask)
}
}
Add routes
func handleGetTasks(request: RouterRequest,
response: RouterResponse,
next: @escaping () -> Void) throws {
}
func handleAddTask(request: RouterRequest,
response: RouterResponse,
next: @escaping () -> Void) throws {
}
Add basic collection to Controller
let tasks: [String] = []
Get tasks
func handleGetTasks(request: RouterRequest,
response: RouterResponse,
next: @escaping () -> Void) throws {
response.status(.OK).send(json: JSON( tasks ))
}
Add ability to add tasks
Add a Body Parser
router.all("*", middleware: BodyParser())
Simplify getting the JSON back
extension RouterRequest {
var json: JSON? {
guard let body = self.body else {
return nil
}
guard case let .json(json) = body else {
return nil
}
return json
}
}
Get the description back
func handleAddTask(request: RouterRequest,
response: RouterResponse,
next: @escaping () -> Void) throws {
if let json = request.json else {
response.status(.badRequest)
next()
return
}
let description = json["description"].stringValue
tasks.append(description)
}
Protect your array
let queue = DispatchQueue(label: "com.example.tasklist")
queue.sync {
}
Create a more rich Task
struct Task {
let id: UUID
let description: String
let createdAt: Date
let isCompleted: Bool
}
Make it Equatible
extension Task: Equatable { }
func == (lhs: Task, rhs: Task) -> Bool {
if lhs.id == rhs.id,
lhs.description == rhs.description,
lhs.createdAt == rhs.createdAt,
lhs.isCompleted == rhs.isCompleted
{
return true
}
return false
}
Make things tranformable to Dictionary
typealias StringValuePair = [String: Any]
protocol StringValuePairConvertible {
var stringValuePairs: StringValuePair {get}
}
Make collections also tranformable to Dictionary
extension Array where Element : StringValuePairConvertible {
var stringValuePairs: [StringValuePair] {
return self.map { $0.stringValuePairs }
}
}
Make Task a StringValuePairConvertible
extension Task: StringValuePairConvertible {
var stringValuePairs: StringValuePair {
return [
"id": "(self.id)",
"description": self.description,
"createdAt": self.createdAt.timeIntervalSinceReferenceDate,
"isCompleted": self.isCompleted
]
}
}
Change [String] to [Task]
private var tasks: [Task] = []
response.status(.OK).send(json: JSON(task.stringValuePairs))
Add task with Tasks
task.append(Task(id: UUID(),
description: "Do the dishes",
createdAt: Date(),
isCompleted: false))
Factor out the Database
final class TaskDatabase {
private var storage: [Task] = []
let queue = DispatchQueue(label: "com.example.tasklist")
func addTask(oncompletion: (Task) -> Void) {
queue.sync {
self.storage.append(task)
oncompletion(task)
}
}
func getTasks(oncompletion: ([Task]) -> Void) {
queue.sync {
oncompletion(self.storage)
}
}
}
Use asynchronous callbacks
Error Handling
TaskListError
enum TaskListError : LocalizedError {
case descriptionTooShort(String)
case descriptionTooLong(String)
case noJSON
Error Description
var errorDescription: String? {
switch self {
case .descriptionTooShort(let string): return "(string) is too short"
case .descriptionTooLong(let string): return "(string) is too long"
case .noJSON: return "No JSON in payload"
}
}
Make it convertible to JSON
extension TaskListError: StringValuePairConvertible {
var stringValuePairs: StringValuePair {
return ["error": self.errorDescription ?? ""]
}
}
Validating the Request
let maximumLength = 40
let minimumLength = 3
struct AddTaskRequest {
let description: String
}
Validate the request
func validateRequest(request: RouterRequest) throws -> AddTaskRequest {
guard let json = request.json else {
throw TaskListError.noJSON
}
let description = json["description"].stringValue
if description.characters.count > maximumLength {
throw TaskListError.descriptionTooLong(description)
}
if description.characters.count < minimumLength {
throw TaskListError.descriptionTooShort(description)
}
return AddTaskRequest(description: description)
}
Use Promises
Add MiniPromiseKit
.Package(url: "https://github.com/davidungar/miniPromiseKit", majorVersion: 4, minor: 1),
Create Promises
final class TaskDatabase {
private var storage: [Task] = []
let queue = DispatchQueue(label: "com.example.tasklist")
func addTask(task: Task) -> Promise<Task> {
return Promise{ fulfill, reject in
queue.sync {
self.storage.append(task)
fulfill(task)
}
}
}
func getTasks() -> Promise<[Task]> {
return Promise{ fulfill, reject in
queue.sync {
fulfill(self.storage)
}
}
}
}
Use the Promises
_ = firstly {
taskDatabase.getTasks()
}.then (on: self.queue) { tasks in
response.status(.OK).send(json: JSON(tasks.stringValuePairs))
}
.catch (on: self.queue) { error in
if let err = error as? TaskListError {
response.status(.badRequest).send(json: JSON(err.stringValuePairs))
}
}
.always(on: self.queue) {
next()
}
Use the Promises
_ = firstly { () throws -> Promise<Task> in
let addRequest = try validateRequest(request: request)
let task = Task(with: addRequest)
return taskDatabase.addTask(task: task)
}
.then (on: self.queue) { task -> Void in
response.status(.OK).send(json: JSON(task.stringValuePairs))
}
.catch (on: self.queue) { error in
if let err = error as? TaskListError {
response.status(.badRequest).send(json: JSON(err.stringValuePairs))
}
}
.always(on: self.queue) {
next()
}
Testing
Set up Kitura framework
private let queue = DispatchQueue(label: "Kitura runloop", qos: .userInitiated, attributes: .concurrent)
public let defaultSession = URLSession(configuration: .default)
private let todoListController = TodoListController()
override func setUp() {
super.setUp()
Kitura.addHTTPServer(onPort: 8090, with: todoListController.router)
queue.async {
Kitura.run()
}
}
Add a test
func testGetTodos() {
let expectation1 = expectation(description: "Get Todos")
var url: URLRequest = URLRequest(url: URL(string: "http://localhost:8090/v1/tasks")!)
url.addValue("application/json", forHTTPHeaderField: "Content-Type")
url.httpMethod = "GET"
url.cachePolicy = URLRequest.CachePolicy.reloadIgnoringCacheData
let dataTask = defaultSession.dataTask(with: url) {
data, response, error in
XCTAssertNil(error)
switch (response as? HTTPURLResponse)?.statusCode {
case 200?:
guard let data = data else {
XCTAssert(false)
return
}
let json = JSON(data: data)
print(json)
expectation1.fulfill()
case nil: XCTFail("response not HTTPURLResponse")
case let code?: XCTFail("bad status: (code)")
}
}
dataTask.resume()
waitForExpectations(timeout: 10, handler: { _ in })
}
Enable Code coverage
swift package generate-xcodeproj --enable-code-coverage

More Related Content

What's hot

The Ring programming language version 1.10 book - Part 50 of 212
The Ring programming language version 1.10 book - Part 50 of 212The Ring programming language version 1.10 book - Part 50 of 212
The Ring programming language version 1.10 book - Part 50 of 212
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.3 book - Part 40 of 184
The Ring programming language version 1.5.3 book - Part 40 of 184The Ring programming language version 1.5.3 book - Part 40 of 184
The Ring programming language version 1.5.3 book - Part 40 of 184
Mahmoud Samir Fayed
 
Scala - den smarta kusinen
Scala - den smarta kusinenScala - den smarta kusinen
Scala - den smarta kusinen
Redpill Linpro
 
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
Amazon Web Services
 
Why realm?
Why realm?Why realm?
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
Mahmoud Samir Fayed
 
Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察
Tsuyoshi Yamamoto
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
Christoffer Noring
 
2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines
Eamonn Boyle
 
The Ring programming language version 1.5.1 book - Part 12 of 180
The Ring programming language version 1.5.1 book - Part 12 of 180The Ring programming language version 1.5.1 book - Part 12 of 180
The Ring programming language version 1.5.1 book - Part 12 of 180
Mahmoud Samir Fayed
 
Async all around us (promises)
Async all around us (promises)Async all around us (promises)
Async all around us (promises)
Francisco Ferreira
 
Codable routing
Codable routingCodable routing
Codable routing
Pushkar Kulkarni
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
Mahmoud Samir Fayed
 
Caching a page
Caching a pageCaching a page
Caching a page
Radha Krishnan
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and Cassandra
Deependra Ariyadewa
 
XTW_Import
XTW_ImportXTW_Import
XTW_Import
Luther Quinn
 
Python in the database
Python in the databasePython in the database
Python in the database
pybcn
 
Finding Clojure
Finding ClojureFinding Clojure
Finding Clojure
Matthew McCullough
 
The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181
Mahmoud Samir Fayed
 

What's hot (20)

The Ring programming language version 1.10 book - Part 50 of 212
The Ring programming language version 1.10 book - Part 50 of 212The Ring programming language version 1.10 book - Part 50 of 212
The Ring programming language version 1.10 book - Part 50 of 212
 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185
 
The Ring programming language version 1.5.3 book - Part 40 of 184
The Ring programming language version 1.5.3 book - Part 40 of 184The Ring programming language version 1.5.3 book - Part 40 of 184
The Ring programming language version 1.5.3 book - Part 40 of 184
 
Scala - den smarta kusinen
Scala - den smarta kusinenScala - den smarta kusinen
Scala - den smarta kusinen
 
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
 
Why realm?
Why realm?Why realm?
Why realm?
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
 
Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
 
2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines
 
The Ring programming language version 1.5.1 book - Part 12 of 180
The Ring programming language version 1.5.1 book - Part 12 of 180The Ring programming language version 1.5.1 book - Part 12 of 180
The Ring programming language version 1.5.1 book - Part 12 of 180
 
Async all around us (promises)
Async all around us (promises)Async all around us (promises)
Async all around us (promises)
 
Codable routing
Codable routingCodable routing
Codable routing
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
 
Caching a page
Caching a pageCaching a page
Caching a page
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and Cassandra
 
XTW_Import
XTW_ImportXTW_Import
XTW_Import
 
Python in the database
Python in the databasePython in the database
Python in the database
 
Finding Clojure
Finding ClojureFinding Clojure
Finding Clojure
 
The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181
 

Similar to Kitura Todolist tutorial

Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
vhazrati
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
Xebia IT Architects
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
IndicThreads
 
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
KAI CHU CHUNG
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
TechWell
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
Paweł Kowalczuk
 
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
Macoscope
 
Spring data iii
Spring data iiiSpring data iii
Spring data iii
명철 강
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
julien.ponge
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
Siarzh Miadzvedzeu
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
Vitali Pekelis
 
Serverless archtiectures
Serverless archtiecturesServerless archtiectures
Serverless archtiectures
Iegor Fadieiev
 
Android Automated Testing
Android Automated TestingAndroid Automated Testing
Android Automated Testing
roisagiv
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
Ben Lin
 
Scala4sling
Scala4slingScala4sling
Scala4sling
day
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
Tsuyoshi Yamamoto
 
Nancy + rest mow2012
Nancy + rest   mow2012Nancy + rest   mow2012
Nancy + rest mow2012
Christian Horsdal
 

Similar to Kitura Todolist tutorial (20)

Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
 
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
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
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
 
Spring data iii
Spring data iiiSpring data iii
Spring data iii
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
Serverless archtiectures
Serverless archtiecturesServerless archtiectures
Serverless archtiectures
 
Android Automated Testing
Android Automated TestingAndroid Automated Testing
Android Automated Testing
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Scala4sling
Scala4slingScala4sling
Scala4sling
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
 
Nancy + rest mow2012
Nancy + rest   mow2012Nancy + rest   mow2012
Nancy + rest mow2012
 

Recently uploaded

Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
Quickdice ERP
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
Hornet Dynamics
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
Peter Muessig
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
lorraineandreiamcidl
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
Hironori Washizaki
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
Grant Fritchey
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
Hornet Dynamics
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 

Recently uploaded (20)

Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 

Kitura Todolist tutorial

  • 2. Creating a TodoList → Creating a project → Add dependencies → Simple Routing → Error Handling → Promises → Testing
  • 3. Create a Project mkdir TodoList cd TodoList swift package init swift package generate-xcodeproj
  • 4. Add Dependencies import PackageDescription let package = Package( name: "MyTodoList", dependencies: [ .Package(url: "https://github.com/IBM-Swift/Kitura", majorVersion: 0, minor: 32), .Package(url: "https://github.com/IBM-Swift/HeliumLogger", majorVersion: 0, minor: 17) ] )
  • 5. Simple Route let router = Router() router.get("/") { request, response, next in response.status(.OK).send("Hello World!") }
  • 6. Simple Server Kitura.addHTTPServer(onPort: 8090, with: todoListController.router) Kitura.run()
  • 8. Using multiple targets targets: [ Target(name: "Server", dependencies: [.Target(name: "TodoList")]), Target(name: "TodoList") ], Separation project to: → Sources/TodoList/TodoList.swift → Sources/Server/main.swift
  • 9. Create a Controller public final class TodoListController { public let router = Router() public init() { router.get("/v1/tasks", handler: handleGetTasks) router.post("/v1/tasks", handler: handlerAddTask) } }
  • 10. Add routes func handleGetTasks(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws { } func handleAddTask(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws { }
  • 11. Add basic collection to Controller let tasks: [String] = []
  • 12. Get tasks func handleGetTasks(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws { response.status(.OK).send(json: JSON( tasks )) }
  • 13. Add ability to add tasks
  • 14. Add a Body Parser router.all("*", middleware: BodyParser())
  • 15. Simplify getting the JSON back extension RouterRequest { var json: JSON? { guard let body = self.body else { return nil } guard case let .json(json) = body else { return nil } return json } }
  • 16. Get the description back func handleAddTask(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws { if let json = request.json else { response.status(.badRequest) next() return } let description = json["description"].stringValue tasks.append(description) }
  • 17. Protect your array let queue = DispatchQueue(label: "com.example.tasklist") queue.sync { }
  • 18. Create a more rich Task struct Task { let id: UUID let description: String let createdAt: Date let isCompleted: Bool }
  • 19. Make it Equatible extension Task: Equatable { } func == (lhs: Task, rhs: Task) -> Bool { if lhs.id == rhs.id, lhs.description == rhs.description, lhs.createdAt == rhs.createdAt, lhs.isCompleted == rhs.isCompleted { return true } return false }
  • 20. Make things tranformable to Dictionary typealias StringValuePair = [String: Any] protocol StringValuePairConvertible { var stringValuePairs: StringValuePair {get} }
  • 21. Make collections also tranformable to Dictionary extension Array where Element : StringValuePairConvertible { var stringValuePairs: [StringValuePair] { return self.map { $0.stringValuePairs } } }
  • 22. Make Task a StringValuePairConvertible extension Task: StringValuePairConvertible { var stringValuePairs: StringValuePair { return [ "id": "(self.id)", "description": self.description, "createdAt": self.createdAt.timeIntervalSinceReferenceDate, "isCompleted": self.isCompleted ] } }
  • 23. Change [String] to [Task] private var tasks: [Task] = [] response.status(.OK).send(json: JSON(task.stringValuePairs))
  • 24. Add task with Tasks task.append(Task(id: UUID(), description: "Do the dishes", createdAt: Date(), isCompleted: false))
  • 25. Factor out the Database final class TaskDatabase { private var storage: [Task] = [] let queue = DispatchQueue(label: "com.example.tasklist") func addTask(oncompletion: (Task) -> Void) { queue.sync { self.storage.append(task) oncompletion(task) } } func getTasks(oncompletion: ([Task]) -> Void) { queue.sync { oncompletion(self.storage) } } }
  • 28. TaskListError enum TaskListError : LocalizedError { case descriptionTooShort(String) case descriptionTooLong(String) case noJSON
  • 29. Error Description var errorDescription: String? { switch self { case .descriptionTooShort(let string): return "(string) is too short" case .descriptionTooLong(let string): return "(string) is too long" case .noJSON: return "No JSON in payload" } }
  • 30. Make it convertible to JSON extension TaskListError: StringValuePairConvertible { var stringValuePairs: StringValuePair { return ["error": self.errorDescription ?? ""] } }
  • 31. Validating the Request let maximumLength = 40 let minimumLength = 3 struct AddTaskRequest { let description: String }
  • 32. Validate the request func validateRequest(request: RouterRequest) throws -> AddTaskRequest { guard let json = request.json else { throw TaskListError.noJSON } let description = json["description"].stringValue if description.characters.count > maximumLength { throw TaskListError.descriptionTooLong(description) } if description.characters.count < minimumLength { throw TaskListError.descriptionTooShort(description) } return AddTaskRequest(description: description) }
  • 35. Create Promises final class TaskDatabase { private var storage: [Task] = [] let queue = DispatchQueue(label: "com.example.tasklist") func addTask(task: Task) -> Promise<Task> { return Promise{ fulfill, reject in queue.sync { self.storage.append(task) fulfill(task) } } } func getTasks() -> Promise<[Task]> { return Promise{ fulfill, reject in queue.sync { fulfill(self.storage) } } } }
  • 36. Use the Promises _ = firstly { taskDatabase.getTasks() }.then (on: self.queue) { tasks in response.status(.OK).send(json: JSON(tasks.stringValuePairs)) } .catch (on: self.queue) { error in if let err = error as? TaskListError { response.status(.badRequest).send(json: JSON(err.stringValuePairs)) } } .always(on: self.queue) { next() }
  • 37. Use the Promises _ = firstly { () throws -> Promise<Task> in let addRequest = try validateRequest(request: request) let task = Task(with: addRequest) return taskDatabase.addTask(task: task) } .then (on: self.queue) { task -> Void in response.status(.OK).send(json: JSON(task.stringValuePairs)) } .catch (on: self.queue) { error in if let err = error as? TaskListError { response.status(.badRequest).send(json: JSON(err.stringValuePairs)) } } .always(on: self.queue) { next() }
  • 39. Set up Kitura framework private let queue = DispatchQueue(label: "Kitura runloop", qos: .userInitiated, attributes: .concurrent) public let defaultSession = URLSession(configuration: .default) private let todoListController = TodoListController() override func setUp() { super.setUp() Kitura.addHTTPServer(onPort: 8090, with: todoListController.router) queue.async { Kitura.run() } }
  • 40. Add a test func testGetTodos() { let expectation1 = expectation(description: "Get Todos") var url: URLRequest = URLRequest(url: URL(string: "http://localhost:8090/v1/tasks")!) url.addValue("application/json", forHTTPHeaderField: "Content-Type") url.httpMethod = "GET" url.cachePolicy = URLRequest.CachePolicy.reloadIgnoringCacheData let dataTask = defaultSession.dataTask(with: url) { data, response, error in XCTAssertNil(error) switch (response as? HTTPURLResponse)?.statusCode { case 200?: guard let data = data else { XCTAssert(false) return } let json = JSON(data: data) print(json) expectation1.fulfill() case nil: XCTFail("response not HTTPURLResponse") case let code?: XCTFail("bad status: (code)") } } dataTask.resume() waitForExpectations(timeout: 10, handler: { _ in }) }
  • 41. Enable Code coverage swift package generate-xcodeproj --enable-code-coverage