てくてくテック

気ままに開発のメモを書いていこうと思います。主にSwiftかと。

Kituraのチュートリアル(ToDoBackend)で気になったことを調べた

はじめに

こんにちは。toosaaです。

前回、Kituraのチュートリアルの一つであるToDoBackendを動かしました。今回は、その中で気になった点について調べます。

Codable プロトコル

Swift4から追加されたプロトコルで、これを使うとjsonとの変換を勝手にやってくれます。すごく便利です参考。 今回のチュートリアルでは、Web APIとしてjsonを返すため利用しているのだと思います。そして、このcodableを使うためkituraのversionは swift4なのだと思います。

Equatable プロトコル

ToDoモデルはCodableプロトコル以外にEquatableプロトコルにも準拠しています。これはKituraとして必要というわけではなく、サンプルのupdateHandler()やdeleteHandler()でArrayの中からオブジェクトを見つけるのに必要だから利用しているようです。let idPosition = todoStore.index(of: idMatch)ここの部分です。

handlerの指定の仕方

チュートリアルだとApplication.swift内にhandlerのメソッドを実装してますが、実運用するにあたってはモデルに紐づけて実装したいです。これは単に、モデルclassにstaticメソッドで同じメソッドを実装すればいいです。とりあえず、データを格納するarray等もstaticにしてしまえば動くものはできます。実際はDBと接続するでしょう。

// Model.swift
extension ToDo{
    static var todoStore = [ToDo]()
    static var nextId :Int = 0
    static let workerQueue = DispatchQueue(label: "worker")
    
    static func storeHandler(todo: ToDo, completion: (ToDo?, RequestError?) -> Void ) {
        var todo = todo
        if todo.completed == nil {
            todo.completed = false
        }
        todo.id = nextId
        todo.url = "http://localhost:8080/\(nextId)"
        nextId += 1
        execute {
            todoStore.append(todo)
        }
        completion(todo, nil)
    }
    
    static func deleteAllHandler(completion: (RequestError?) -> Void ) {
        execute {
            todoStore = [ToDo]()
        }
        completion(nil)
    }
    
    static func getAllHandler(completion: ([ToDo]?, RequestError?) -> Void ) {
        completion(todoStore, nil)
    }
    
    static func getOneHandler(id: Int, completion: (ToDo?, RequestError?) -> Void ) {
        completion(todoStore.first(where: {$0.id == id }), nil)
    }
    
    static func updateHandler(id: Int, new: ToDo, completion: (ToDo?, RequestError?) -> Void ) {
        guard let idMatch = todoStore.first(where: { $0.id == id }),
            let idPosition = todoStore.index(of: idMatch) else { return }
        var current = todoStore[idPosition]
        current.user = new.user ?? current.user
        current.order = new.order ?? current.order
        current.title = new.title ?? current.title
        current.completed = new.completed ?? current.completed
        execute {
            todoStore[idPosition] = current
        }
        completion(todoStore[idPosition], nil)
    }
    
    static func deleteOneHandler(id: Int, completion: (RequestError?) -> Void ) {
        guard let idMatch = todoStore.first(where: { $0.id == id }),
            let idPosition = todoStore.index(of: idMatch) else { return }
        execute {
            todoStore.remove(at: idPosition)
        }
        completion(nil)
    }
    
    static func execute(_ block: (() -> Void)) {
        workerQueue.sync {
            block()
        }
    }
}
// Application.swift
router.get("/", handler: ToDo.getAllHandler)
router.get("/", handler: ToDo.getOneHandler)
router.post("/", handler: ToDo.storeHandler)
router.delete("/", handler: ToDo.deleteAllHandler)
router.delete("/", handler: ToDo.deleteOneHandler)
router.patch("/", handler: ToDo.updateHandler)

終わりに

次は、Bluemix上でこのアプリを動作させる方法について書こうかと思います。