はじめに

Swift がオープンソースになってからいろいろと盛り上がっているので、その中からサーバーサイド Swift の一つである IBM の Kitura を紹介します。

注意事項

Swift 3 と Kitura はともにまだ開発中のため、新しいバージョンだと記載内容と異なる部分がある可能性があります。
ここで使用したバージョンは以下のとおりです。

Software Version
Swift DEVELOPMENT-SNAPSHOT-2016-05-03-a
Kitura 0.16.0

Kitura とは

IBM が開発した Swift 用の Web フレームワークです。

Kitura の導入

  1. 適当なディレクトリを作成
  2. 作成したディレクトリの直下で以下のコマンドを実行

    swift build –init

  3. Package.swift を編集

    import PackageDescription
      let package = Package(
      name: "KituraTutorial",
      dependencies: [
        .Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 0, minor: 16)
      ]
    )
    
  4. swift build –fetch を実行し、Kitura のパッケージをダウンロード

  5. お好みで Xcode を使ってコードを書きたいときは swift build –generate-xcodeproj を実行しプロジェクトファイルを作成

導入手順の解説

swift build –init を実行することで、アプリケーション開発のための下準備が行われます。 Swift Package Manager により以下のような構成でファイルが作成されます。

.
+-- Package.swift
+-- .gitignore
+-- Sources
|   +-- main.swift
+-- Tests

Package.swift は、Swift Package Manager でのマニフェストファイルです。
Package.swift にはビルドの設定や依存関係を記載します。
今回は Kitura を使用するので、以下のように依存関係に Kitura を追加します。

dependencies: [
  .Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 0, minor: 16)
]

Package.swift の書き方の詳細は、Package.swift — The Manifest File を参考にしてください。

swift build –fetch は、依存しているパッケージを取得するコマンドです。
このコマンドを実行すると、Packages ディレクトリ以下に依存しているパッケージがダウンロードされます。
また、依存しているパッケージの更新をするときは swift build –update を実行します。

アプリ作成

Sources/main.swift を編集してアプリを作成します。

モジュールのインポート

Kitura を使用するので、まずモジュールのインポートを行います。

import Kitura

ルーターの作成

アクセスする URL と、その URL にアクセスされた時に実行する処理を紐付けるためにルーターを作成します。 ルーターは、Router クラスのインスタンスです。

let router = Router()

アクセスされた時の処理の実装

GET や POST などのメソッドでアクセスされた場合の処理は、それぞれルーターの対応するメソッドを使用して定義します。

HTTP メソッド Kitura
GET get(_:handler:), get(_:middleware:)
POST post(_:handler:), post(_:middleware:)
PUT put(_:handler:), put(_:middleware:)
HEAD head(_:handler:), head(_:middleware:)
DELETE delete(_:handler:), delete(_:middleware:)
OPTIONS options(_:handler:), options(_:middleware:)
TRACE trace(_:handler:), trace(_:middleware:)

handlerRouterHandler としてエイリアス定義されているクロージャで、
実体は (request: Kitura.RouterRequest, response: Kitura.RouterResponse, next: () -> Swift.Void) -> Swift.Void となります。
middleware は、プロトコル RouterMiddleware のインスタンスを指定します。

エンドポイント /entry に GET でアクセスされた時の処理は、以下のような形で記述します。

router.get("/entry") { request, response, next in
  // GET の場合の処理
  ...

  next()
}

レスポンスとして、ステータスコードを指定したい場合は、response.status(_:) を呼び出します。
response.status(_:) は、列挙型 KituraNet.HTTPStatusCode を引数として受け取ります。
例えばステータスコード 403 (Forbidden) を設定したいときは、response.status(.forbidden) とします。

データの送受信

  • クライアントに送信する場合
クライアント側にデータを送信する場合、RouterResponsesend メソッドを呼び出します。 send メソッドは、以下のように異なる引数を受け取ります。
メソッド 送信データの種類
send(_:) 文字列
send(data:) NSData
send(fileName:) ファイル
send(json:) JSON

文字列を送信する場合は、以下のように書きます。

response.send("Some contents...")

Kitura では SwiftyJSON を使用しています。 JSON を送信する場合、SwiftyJSON を使用して JSON のオブジェクトを作成し send(json:) で送信します。

let dic = ["key": "value"]
let json = JSON(dic)
response.send(json: json)
  • クライアントから受信する場合
クライアントからデータを受信する時はミドルウェアの設定を行う必要があります。 Kitura には、BodyParser というミドルウェアが用意されています。 BodyParser を使うと、JSON とプレーンテキストの受信ができるようになります。 ミドルウェアを使用してボディからデータを取得する時は、以下のように書きます。
router.post("/entry", middleware: BodyParser())
router.post("/entry") { request, response, next in
  if let body = response.body {
    // POST の場合の処理
    ...
  }
  next()
}

ボディは列挙型 ParsedBody のインスタンスとして取得できます。 JSON とプレーンテキストを受信する場合、以下のように切り分けを行います。

switch body {
case .json(let json):
  // JSON を受け取った時の処理
  ...
case .text(let string):
  // プレーンテキストを受け取った時の処理
  ...
default:
  break
}

クエリー

クエリーは、RouterRequest のプロパティ queryParams に格納されています。 queryParams[String:String] 型で定義されているので以下のように扱います。

if request.queryParams.contains({ return $0.key == "type" }) {
  let value = request.queryParams["type"]
  // クエリー "type" の処理
  ...
}

パラメーター

http://example.com/user/1234 にアクセスし、ユーザー ID 1234 のユーザーの情報を取得する場合を考えてみます。 この時、/user/:user_iduser_id というパラメーターの取得をルーターで行う必要があります。 このような場合は以下のように書きます。

router.get("/user/:user_id") { request, response, next in
  if let userID = request.params["user_id"] {
    // 指定したユーザー ID の処理
    ...
  }
  next()
}

上記の例では、["user_id":"URLで指定された値"]request.params になります。
http://example.com/user/1234 にアクセスがあった場合には、["user_id":"1234"] がパラメーターになります。
request.params は、[String:String] として定義されていますので、数値などの文字列以外の型の場合は、ここから、さらに変換処理を行います。

HTTP サーバーの作成と開始

作成したルーターを使用して、HTTP サーバーの作成し、サーバーを起動させます。 サーバーの起動は、以下のように行います。

Kitura.addHTTPServer(onPort: 8090, with: router)
Kitura.run()

ビルド

swift build を実行し、アプリをビルド。指定がない場合は、デバッグ版としてビルドされます。
リリース版をビルドする場合は、swift build –release を実行します。

実行

.build ディレクトリ以下にアプリは作成されます。

configuration directory
デバッグ版 .build/debug
リリース版 .build/release

上記のディレクトリから、アプリを実行します。
アプリ実行後、http://localhost:8090/ にアクセスすると、動いているのが確認できます。

まとめ

今回はサーバーサイド Swift のフレームワークとして、IBM の Kitura を紹介しました。 Swift を触ったことがあれば、お手軽にサーバーサイドを実装できることがお分かりいただけたのではないでしょうか。