読者です 読者をやめる 読者になる 読者になる

Intensive Programmer

技術的なことや読書感想などなど...

Vapor触ってみた〜その2〜

あけましておめでとうございます。@suzukai74です。

前回の続きでVaporでCRUDを実装していきます。


と思ったけど、ほとんどプロジェクト作成時にひな形が作られています。
ディレクトリ構成はこんなカンジ

tree
.
├── app.json
├── Config
│   ├── app.json
│   ├── clients.json
│   ├── crypto.json
│   ├── droplet.json
│   ├── production
│   │   └── app.json
│   └── servers.json
├── license
├── Localization
│   ├── default.json
│   ├── en-US.json
│   ├── es-US.json
│   ├── nl-BE.json
│   └── nl-NL.json
├── Package.swift
├── Procfile
├── Public
│   ├── images
│   │   └── vapor-logo.png
│   └── styles
│       └── app.css
├── README.md
├── Resources
│   └── Views
│       ├── base.leaf
│       └── welcome.leaf
└── Sources
    └── App
        ├── Controllers
        │   └── PostController.swift
        ├── main.swift
        └── Models
            └── Post.swift

既にコントローラにPostController.swift、モデルにPost.swiftとそれぞれできている。

方針

ひな形がある程度揃っているので、データベースのつなぎ込みを行い、
データの登録削除更新をできるようにする

実装

データべースはMySQLを使用します。
※インストール、データベース作成部分は省略します。
今回はvaporという名前でデータベースを作成します。

Config/mysql.jsonを作成する

{
    "host": "localhost",
    "user": "root",
    "password": "",
    "database": "vapor"
}


Package.swiftにmysql-providerを追加。

import PackageDescription
  
let package = Package(
    name: "Hello",
    dependencies: [
        .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 1),
        .Package(url: "https://github.com/vapor/mysql-provider.git", majorVersion: 1, minor: 1) // 追加
    ],
    // 以下省略
)

Sources/App/main.swftにMySQLプロバイダを追加する

import Vapor
import VaporMySQL // 追加
import HTTP

// 以下のように修正
let drop = Droplet(
    providers: [VaporMySQL.Provider.self] 
)

// 以下省略

モデルをMySQLと紐付け

Sources/App/Models/Post.swiftを以下のように修正する

import Vapor
import Fluent
import Foundation

final class Post: Model {
    var id: Node?
    var content: String
    
    init(content: String) {
        self.content = content
    }

    init(node: Node, in context: Context) throws {
        id = try node.extract("id")
        content = try node.extract("content")
    }

    func makeNode(context: Context) throws -> Node {
        return try Node(node: [
            "id": id,
            "content": content
        ])
    }
}

extension Post: Preparation {
    static func prepare(_ database: Database) throws {
        // 以下追加
        try database.create("posts") { posts in
            posts.id()
            posts.string("content")
        }
    }

    static func revert(_ database: Database) throws {
        try database.delete("posts") // 追加
    }
}

prepareはアプリ起動時に呼ばれます。
revertはvapor run prepare --revertコマンド実行時に呼ばれます。

ルーティング

Sources/App/main.swftのDropletにpreparationsを追加する

import Vapor
import VaporMySQL
import HTTP

let drop = Droplet(
    preparations: [Post.self],  // 追加
    providers: [VaporMySQL.Provider.self]
)

drop.resource("posts", PostController())

drop.run()

drop.resource("posts", PostController())は下記のURLに対応している

アクション URL HTTPメソッド 概要
index /posts GET 全postを取得
create /posts POST 新規postを作成
show /posts/{id} GET 任意のpostを取得
delete /posts/{id} DELETE 任意のpostを削除
clear /posts DELETE 全postを削除
update /posts/{id} PATCH 任意のpostを更新
replace /posts/{id} PUT 任意のpostを置き換え

コントローラ

Sources/App/Controllers/PostController.swiftはデフォルトのままでOKです。

動作確認

vapor run serveでサーバを起動する。

データの追加

コンソールで下記コマンドを実行

curl http://localhost:8080/posts -X POST -d "post[content]=test"

データの一覧

ブラウザでhttp://localhost:8080/postsにアクセス

[{"content":"test","id":1}]

と表示される。

任意のデータ取得

ブラウザでhttp://localhost:8080/posts/1にアクセス

{"content":"test","id":1}

と表示される。

データの更新

コンソールで下記コマンドを実行

curl http://localhost:8080/posts/1 -X PATCH -d "post[content]=new_test"

ブラウザでhttp://localhost:8080/posts/1にアクセス

{"content":"new_test","id":1}

と表示されれば、正しく更新が行われている。

データの削除

コンソールで下記コマンドを実行

curl http://localhost:8080/posts/1 -X DELETE

ブラウザでhttp://localhost:8080/postsにアクセス

[]

と表示されれば、正しく削除が行われている。

まとめ

CRUDの機能を一通り実装しましたが、ほとんどひな形のままでいけましたw
Vaporは公式のドキュメントが揃っているので、いろいろ試していきたいです。
いいデバッグ方法がありましたら、教えていただきたいです。