VaporアプリケーションでAPIを作る(SQLiteファイルからデータ取得する編)

はじめに

牛の歩み。

MongoDBに辿り着く前にFluentSQLiteの沼に足を取られてしまっています。SQLLiteデータベースにデータを保存できたので、今度は取得してみます。

追加した本のデータを取得してみる

ここでもFluentSQLiteの威力が発揮されます。FluentSQLite先輩ぱねえ!

全部持ってくる

データベースのテーブル内にあるデータ全部を持ってきます。

router.get("api/books") { req -> Future<[Book]> in
    return Book.query(on: req).all()
}

SQLiteModelプロトコルに準拠しているため、何もしなくてもqueryメソッドが使えます。しかもFutureのことをほとんど意識せずに使えます。なんということでしょう!

PostmanでもブラウザでもどちらでもOKです。ブラウザで試してみます。

データベース上のすべてのデータを取得してくることができました

idを指定して特定のデータを持ってくる

こちらのほうが実用的かもです。

router.get("api/book",Book.parameter) { req -> Future<Book> in
    return try req.parameters.next(Book.self)
}

ここでのキモはBook.parameterです。RouteでInt型のパラメータを受け取るためには、router.get("api/book",Int.parameter)となります。でも、パラメータで渡したい値がSQLiteModelのPrimaryKeyならば違います。そう、FluentSQLiteのデータモデルならね。多分。

なんと、Book.parameteを使うことで自動的にPrimaryKeyのことを指してくれるそうです。英語の壁が高すぎて、本当かどうか確信が持てないところが辛いですが、そうらしいです。

アプリケーションを実行し、http://localhost:8080/api/book/2を叩いてみると、idが2のBookエンティティを引っ張ってくれます。パラメータに2しか入れていないのにBookエンティティが取得できるとは不思議。req.parameters.next(Book.self)を実行すると2が返ってきそうなのに
Bookエンティティが返ってくる不思議。

おそらくパラメータも返ってくるデータもBookエンティティが動いているのでしょう。ただ、APIで渡すパラメータにはidを渡すだけでBookエンティティと関連付けが行われているのでしょう。推測ですが、そのうち理解できると思います。

id以外を指定してデータを持ってくる

プロパティがしょぼいのですが、がんばります。出版社(Publisher)であいまい検索をしてみます。今更ですが、プロパティ名がpublishになっていました。動詞なのでこれは良くない。今気づいたので今修正しておきます。
横道にそれますが、気づいたらその場で修正しておかないと、修正する機会は二度と訪れないと思っておいたほうが良いと考えています。

router.get("api/books",String.parameter) { req -> Future<[Book]> in
    // 大文字英数字で入力されることも考慮してlowercased()をつけてみたりしました。
    let publisher = try req.parameters.next(String.self).lowercased()
    // filterで絞り込み、ソートし、全部返してもらうチェーン
    // filterのチェーンもできますよ(出版社であいまい検索した結果を更に書名であいまい検索など)
    return Book.query(on: req).filter(\.publisher, ._like, "%" + publisher + "%").sort(\.title, .descending).all()
}

ここで重要なことはfilterに渡すクエリです。filterと入れるとXCodeがいくつか候補を出してくれますが、filter(key: ~, method: ~, value: ~)で指定するやつのほうが細かく書けるので便利です。リファレンスで探すとfilter(_:_:_:)と出ていて分かりにくかった。

OraなんたらさんやSQLSerなんたらさんに投げるSQLのWhere句に書くように書くことができます。
上記の例ではプロパティpublisherにパラメータで渡した値publisherで部分一致検索を行っています。意味合い的にはパラメータで出版を渡したと仮定してwhere pubisher like '%出版%'と一緒ですね。書き方もよく似ているので抵抗感は小さいと思います。

「等しい」とか「よりも大きい」とか、シンプルな条件を書くならば、filter(_:)で式を書いてしまうのが良いと思います。特定の出版年で抽出したいときなどはこちらがわかりやすいです。filter(\.出版年 = 2003)のように書けます。

まとめ

SQLiteデータベースを叩いてデータの取得ができるようになりました。いよいよ次はSQLite最後のシメのデータの更新と削除です。あやふやふわふわ進めていますが、私は元気です。そのうち理解できるでしょう。それよりも早くSQLiteではなく当初の目的のMongoDBを叩きたい。