hello.serversideswift.netの作り方

このサイトはHTMLをレンダリングして返しているだけの単純なものですが、一応サーバーサイドSwiftの一例です。
ここでは、その作り方を説明します。

更新日 2017/3/18
Xcode 8.2.1
Swift 3.0.2
Kitura 1.3
OS X 10.11.6

Kitura-Starter

無料枠で常時公開が可能な、Bluemixを利用させてもらいます。
フレームワークには同じくIBMが提供しているKituraを使います。

KituraのプロジェクトをBluemixにデプロイするなら、Kitura-Starterをベースにするのが便利です。
まずはREADMEにしたがって、ローカルで動かします。

$ swift --version
Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)
Target: x86_64-apple-macosx10.9

$ git clone https://github.com/IBM-Bluemix/Kitura-Starter.git serversideswift.net
$ cd serversideswift.net/

$ swift build
$ ./.build/debug/Kitura-Starter

この状態で、http://localhost:8090/上で動くようになります。

Sources/Kitura-Starter/Controller.swiftを見てみると、public/index.htmlをそのまま返しているようです。

router.all("/", middleware: StaticFileServer())

Xcode

Vaporのようなツールはありませんが、Swift Package Mangerの機能を使えばXcodeプロジェクトを生成できます。

$ swift package generate-xcodeproj

ただ、うまく動かないことがあるので、僕は普段使っているテキストエディタで開発しています。
(Vaporはtest以外Xcodeを使っています)

Markdownでコンテンツを書けるようにする

コンテンツはやはりMarkdownで書きたいので、その対応をします。

最低限の方法は、Serving content written in Markdown using Kitura - Swift@IBMに載っています。
今回は、layoutなども実現したかったので、IBM-Swift/Kitura-StencilTemplateEngineと組み合わせました。

Package.swift

dependenciesを追加します。

.Package(url: "https://github.com/IBM-Swift/Kitura-Markdown.git", majorVersion: 0, minor: 5),
.Package(url: "https://github.com/IBM-Swift/Kitura-StencilTemplateEngine", Version(1, 4, 0)),

Sources/Kitura-Starter/Controller.swift

Template Engineをimportし、initでRouterの設定をします。

import KituraMarkdown
import KituraStencil

init() throws {
  appEnv = try CloudFoundryEnv.getAppEnv()

  // All web apps need a Router instance to define routes
  router = Router()

  router.add(templateEngine: StencilTemplateEngine())

  router.get("/") { _, response, next in
    try self.renderMarkdown(response: response, filename: "index")
    next()
  }

  router.get("/:id") { request, response, next in
    if let id = Int(request.parameters["id"] ?? "") {
      try self.renderMarkdown(response: response, filename: String(id))
    }
    next()
  }

  // Serve static content from "public"
  router.all("/", middleware: StaticFileServer())
}

これで、Markdownで記事をかけるようになりました。
/ならindex.md/1なら1.mdを使います。

Textlintの導入

1人で長文を書くのは辛いものです。機械に日本語をチェックしてもらいましょう。
(Node.jsの環境が必要です。)

package.json

{
  "name": "serversideswift.net",
  "scripts": {
    "lint": "textlint -f pretty-error Views/*.md; exit 0"
  },
  "devDependencies": {
    "textlint": "^7.2.1",
    "textlint-rule-preset-ja-technical-writing": "^0.1.3"
  }
}

.textlintrc

{
    "rules": {
        "preset-ja-technical-writing": true
    }
}
$ node -v
v6.9.1

$ npm install

これで以下のようにおかしな表現があると指摘してくれます。

$ npm run lint

> serversideswift.net@ lint /path/to/serversideswift.net
> textlint -f pretty-error Views/*.md; exit 0

preset-ja-technical-writing/no-doubled-joshi: 一文に二回以上利用されている助詞 "に" がみつかりました。
/path/to/serversideswift.net/Views/index.md:3:11
                            v
    2.
    3. 公式サイトにある手順にしたがってください。
    4.
                            ^

✖ 1 problem (1 error, 0 warnings)

細かい調整

公開するための準備です。

本質的な部分ではないので詳細は割愛します。

デプロイ

準備

クレジットカード情報の登録

Bluemixには30日間の無料トライアルがあります。
僕は無料トライアルが終わってしまっていたので、本登録をしました。

スペースの作成

米国南部地域を選択するとスペースが無かったのでdevを作成しました。
(昔は自動で作られていたようです。 )

公開

コマンドラインツールを使います。

https://github.com/cloudfoundry/cli/releasesからMac OS X 64 bitをダウンロードして導入します。

ログイン

$ cf -v
cf version 6.23.0+c7866be18-2016-12-22

$ cf api https://api.ng.bluemix.net
Setting api endpoint to https://api.ng.bluemix.net...
OK

API endpoint:   https://api.ng.bluemix.net
API version:    2.54.0
Not logged in. Use 'cf login' to log in.

$ cf login -u メールアドレス -o 組織名 -s スペース名
API endpoint: https://api.ng.bluemix.net

Password>
Authenticating...
OK

Targeted org 組織名

Targeted space スペース名



API endpoint:   https://api.ng.bluemix.net (API version: 2.54.0)
User:           ユーザー名
Org:            組織名
Space:          スペース名

buildpacksの確認

Swiftのbuildpackが含まれていれば問題ありません。

$ cf buildpacks
Getting buildpacks...

buildpack                               position   enabled   locked   filename
liberty-for-java                        1          true      false    buildpack_liberty-for-java_v3.6-20161209-1351.zip
sdk-for-nodejs                          2          true      false    buildpack_sdk-for-nodejs_v3.9-20161128-1327.zip
dotnet-core                             3          true      false    buildpack_dotnet-core_v1.0.6-20161205-0912.zip
swift_buildpack                         4          true      false    buildpack_swift_v2.0.2-20161118-1326.zip
noop-buildpack                          5          true      false    noop-buildpack-20140311-1519.zip
java_buildpack                          6          true      false    java-buildpack-v3.6.zip
ruby_buildpack                          7          true      false    ruby_buildpack-cached-v1.6.16.zip
nodejs_buildpack                        8          true      false    nodejs_buildpack-cached-v1.5.11.zip
go_buildpack                            9          true      false    go_buildpack-cached-v1.7.5.zip
python_buildpack                        10         true      false    python_buildpack-cached-v1.5.5.zip
xpages_buildpack                        11         true      false    xpages_buildpack_v1.2.1-20160913-1038.zip
php_buildpack                           12         true      false    php_buildpack-cached-v4.3.10.zip
staticfile_buildpack                    13         true      false    staticfile_buildpack-cached-v1.3.6.zip
binary_buildpack                        14         true      false    binary_buildpack-cached-v1.0.1.zip
liberty-for-java_v3_4_1-20161030-2241   15         true      false    buildpack_liberty-for-java_v3.4.1-20161030-2241.zip
swift_buildpack_v2_0_1-20161103-0928    16         true      false    buildpack_swift_v2.0.1-20161103-0928.zip
sdk-for-nodejs_v3_8-20161006-1211       17         true      false    buildpack_sdk-for-nodejs_v3.8-20161006-1211.zip
liberty-for-java_v3_5-20161114-1152     18         true      false    buildpack_liberty-for-java_v3.5-20161114-1152.zip
dotnet-core_v1_0_1-20161005-1225        19         true      false    buildpack_dotnet-core_v1.0.1-20161005-1225.zip
xpages_buildpack_v1_2_1-20160913-103    20         true      false    xpages_buildpack_v1.2.1-20160913-1038.zip

manifest.yml

nameを変更して、random-routeを削除しました。
memoryは512M以内なら無料枠でおさまるはずなのでそのままにしました。

applications:
  name: serversideswift-net
  memory: 256M
  instances: 1
  random-route: true
  disk_quota: 1024M
  command: Kitura-Starter
  buildpack: swift_buildpack

push

$ cf push

これで、https://serversideswift-net.mybluemix.net/でもローカルと同じ画面が見られるようになります。

独自ドメインの設定

UIは変わっていますが、こちらの記事が参考になりました。

  1. アプリ一覧から対象のアプリを選択
  2. アプリの表示の横にある三角をマウスオーバー
  3. ドメインの管理から、ドメインを追加
  4. 経路の編集からアプリに追加

という流れです。

今回はserversideswift.netドメインを追加して、helloを経路として追加しました。 参考までに僕の設定画面をキャプチャしておきます。 (画像は古いものでwwwを設定した時のものになっています)

あとはCNAMEを設定すれば、https://hello.serversideswift.net/でもアクセスできるようになります。

hello.serversideswift.netの作り方は以上です。
ソースコードはtnantoka/hello.serversideswift.netで公開しています。