Swift3.0でPostgreSQLに接続して結果をJSONで返してみた

Qiitaでは初めまして。
SwiftでPostgreSQLに接続しようとして苦戦したのでそのメモを兼ねたサンプルです。

# 動作確認環境
|  | バージョン |
|:--|:--|
|OS|Ubuntu 16.04.1 LTS|
|Swift|swift-3.0.1-RELEASE(公式のビルド済みファイルを使用)|
|PostgreSQL|9.5.5|

|  | バージョン |
|:--|:--|
|IBM-Swift/Kitura|1.2.2|
|Zewo/PostgreSQL|0.14.3|

# 下準備
最低限、以下のコマンドを実行しておいてください。
```sudo apt-get install clang libicu-dev libcurl4-openssl-dev libssl-dev libpq-dev```

SwiftとPostgreSQL自体のセットアップは省略しますが、下記の状態と想定して話をします。
 
- PostgreSQL
    - ロール(ユーザー)名
        - swiftsample
    - パスワード
        - swiftsample
    - データベース名
        - swiftsample
    - データベースサーバーのURL
        - localhost
- Swift
    - PATH設定済み

そして、swiftsampleデータベース上で、以下のクエリが実行済みの状態です。

```postgres
CREATE TABLE IF NOT EXISTS profiles (
  user_id INT NOT NULL PRIMARY KEY,
  name text NOT NULL
);
INSERT INTO profiles(user_id,name) VALUES
(1,'Taro Tanaka'),
(2,'Jiro Yamada'),
(3,'Saburo Kato'),
(4,'Shiro Sato'),
(5,'Goro Watanabe');
```

# 実際にやってみる
Swift Package Managerを利用するために、プロジェクトを作成したいディレクトリへ移動済みのターミナルで
```swift package init --type executable```
を実行。
実行したらそのディレクトリにPackage.swiftというファイルやSourceディレクトリなどが作成されます。
Package.swiftは下記のようにしてください。

```swift:Package.swift
import PackageDescription

let package = Package(
    name: "your package name",
    dependencies: [
        .Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 1, minor: 2),
        .Package(url: "https://github.com/Zewo/PostgreSQL.git", majorVersion: 0, minor: 14)
    ]
)
```

Sourcesディレクトリに移動して、Data.swiftを作成し、次のように書いてみてください。

```swift:Data.swift
import SQL

import Foundation

enum SampleField: String, ModelField {
  case userId = "user_id"
  case name = "name"

  static let tableName: String = "profiles"
  static let primaryKey: SampleField = .userId
}

struct Sample {
  let userId:Int
  let name:String
}

extension Sample: ModelProtocol {
    typealias Field = SampleField
    typealias PrimaryKey = Int

    func serialize() -> [Field : ValueConvertible?] {
        return [
            .userId: userId,
            .name: name
        ]
    }

    init<Row: RowProtocol>(row: TableRow<Sample, Row>) throws {
        userId = try row.value(.userId)
        name = try row.value(.name)
    }
}
```

次に同じディレクトリにあるmain.swiftを次のように書き換えてみてください。

```swift:main.swift
import Kitura
import SQL
import PostgreSQL
import SwiftyJSON

import Foundation

let user = "swiftsample"
let password = "swiftsample"
let dbUrl = "localhost"
let dbName = "swiftsample"

enum SampleError: Error {
  case urlNilError // URLがnilだったとき
}

do{
  guard let url = URL(string: "postgres://\(user):\(password)@\(dbUrl):5432/\(dbName)") else {
    throw SampleError.urlNilError
  }
  let db = try PostgreSQL.Connection(info: .init(url))
  try db.open()
  let getDatabase:((RouterRequest,RouterResponse)->()) = { request,response in
    do{
      let fetch:[PersistedEntity<Sample>]
      if let id = request.parameters["id"] {
        fetch = try Entity<Sample>.fetch(where: SampleField.userId == id,connection: db)
      }else{
        fetch = try Entity<Sample>.fetchAll(connection: db)
      }
      var arr:[[String:Any]] = []
      fetch.forEach{ entity in
        let model = entity.model
        let id = model.userId
        let name = model.name
        arr.append([
          "user_id":id,
          "name":name
        ])
      }
      try response.send(json: JSON(arr)).end()
    }catch(let e){
      print("[エラーが発生したよ！]")
      print(e)
    }
  }
  let router = Router()
  router.get("/:id(\\d+)") { request, response, _ in
    getDatabase(request,response)
  }
  router.get("/") { request, response, _ in
    getDatabase(request,response)
  }
  Kitura.addHTTPServer(onPort: 8090, with: router)
  Kitura.run()
}catch(let e){
  print("[エラーが発生したよ！]")
  print(e)
}
```

あとはプロジェクトのルートディレクトリ(Package.swiftがあるディレクトリ)でビルドコマンドの
```swift build -Xcc -I/usr/include/postgresql```
を実行して、エラーがなく、正常にビルドされた場合は
```(プロジェクトのルートディレクトリ)/.build/debug/(プロジェクト名)```
を実行するとHTTPサーバーが8090番ポートで立ち上がります。
実際にアクセスしてみるとJSONが吐き出されるっていう感じになります。

以上です。

#参考にしたページ
[Zewoを用いてサーバサイドでSwiftを利用する](http://qiita.com/shingt/items/0e61962b10375fe28abc)