Vaporとは
Swift製のWeb Frameworkです。
macOS, Ubuntuで動くサーバーサイドのプログラムをSwiftで簡単に書くことができます。
Vaporで作るアプリケーションの設定
今回は、このVaporのアプリケーションの設定値の設定方法を見ていきたいと思います。
Vaporではアプリケーションの設定を次の2通りの方法で指定することができます。
- jsonの設定ファイルに設定を記述
- コマンドライン起動時のオプションで指定
これら2通りの方法について説明します。
1. jsonの設定ファイルに設定を記述
ドキュメントはこちらをご覧ください。
https://vapor.github.io/documentation/guide/config.html#quickstart
任意の名前のjsonファイルに任意の設定値を記述し、アプリケーションコードから使用することができます。
ただし、それにはルールと使い方があるので、それらをみていきましょう。
▶︎ 設定ファイルの置き場所
設定ファイルはプロジェクトの Config/
ディレクトリ下に置いていきます。
WorkingDirectory/
├── Config/
│ ├── server.json
▶︎ 設定ファイルの書き方
設定ファイルは単純にjsonファイルなので、例えば次のように書きます。
{
"http": {
"host": "0.0.0.0",
"port": 8080
}
}
▶︎ アプリケーションコードでの設定値の使い方
{
"string_value": "hoge",
"int_value": 123,
"array_value": [
"fuga",
"piyo"
],
"nest": {
"nested_value": "nested"
}
}
上記のようなjsonファイルで設定した値をコード内で使うには以下のような書式になります。
let drop = Droplet()
// drop.config[fileName, path, to, key...]
drop.config["settings", "string_value"]?.string // Optional("hoge")
drop.config["settings", "int_value"]?.int // Optional(123)
drop.config["settings", "array_value", 1]?.string // Optional("piyo")
drop.config["settings", "nest", "nested_value"]?.string // Optional("nested")
config
のサブスクリプトの1つ目が対象のファイル名、2つ目以降がキーの名前になっています。
設定ファイルがjsonなので、キーがネストされている場合には、2つ目以降のキーの名前をネストされたキーを辿って記述することで最終的な値を得ることができます。
// drop.config[fileName, path, to, key...]
drop.config["server", "http", "host"]?.string // Optional("0.0.0.0")
- ネストされた設定値の応用編
次のような形で、pathIndexableObject
を使用して[String : Config]
型で受け取ることで、ネストされた設定値を変数を介して後から取得することもできます。
let serverSettings = drop.config["server", "http"]?.pathIndexableObject
let host = serverSettings?["host"]?.string // Optional("0.0.0.0")
let port = serverSettings?["port"]?.int // Optional(8080)
▶︎ 環境に合わせた設定値
設定ファイルは Config/
下に置くと書きましたが、 Config/
下にもさらにディレクトリを分けて環境ごとに設定値を変えることができます。
Config/
下には通常、以下の3つのディレクトリが想定されています。
-
Config/production
- production環境の時にこのディレクトリ内の設定ファイルが優先的に読まれます。
-
Config/development
- development環境の時にこのディレクトリ内の設定ファイルが優先的に読まれます。
-
Config/secrets
- どの環境においても最優先でこのディレクトリ内の設定ファイルが読まれます。
- このディレクトリ内はデフォルトでgit管理下から外されています。(
.gitignore
の対象)
使い方としては、
-
Config/
直下の設定ファイルでデフォルト値を設定 - 各環境にて上書きしたい設定に関しては、環境ごとのディレクトリ内にも同じファイル名・同じ構造の設定ファイルを設置
- ローカル環境で最優先で上書きしたい設定を
Config/secrets/
以下に同じファイル名・同じ構造で設置
という感じになるかと思います。
これらの設定は任意ですが、
こういった優先度のルールを知っておくことで、設定の変更が柔軟に行えるかと思います。
# Config/secrets/server.json が読まれる
WorkingDirectory/
├── Config/
│ ├── server.json
│ ├── production/
│ │ └── server.json
│ ├── development/
│ │ └── server.json
│ └── secrets/
│ └── server.json
# development環境では Config/development/server.json 、
# production環境では Config/production/server.json が読まれる
WorkingDirectory/
├── Config/
│ ├── server.json
│ ├── production/
│ │ └── server.json
│ ├── development/
│ │ └── server.json
│ └── secrets/
# development環境では Config/server.json、
# production環境では Config/production/server.json が読まれる
WorkingDirectory/
├── Config/
│ ├── server.json
│ ├── production/
│ │ └── server.json
│ ├── development/
│ └── secrets/
2. コマンドライン起動時のオプションで指定
ドキュメントはこちらをご参照ください。
https://vapor.github.io/documentation/guide/config.html#command-line
▶︎ 優先度
コマンドラインでの指定は、前述のjsonファイルの設定よりも適応の優先度が高いので、設定ファイルの設定を無視してこちらの設定が適応されます。
▶︎ 書き方と使い方
先ほどの例と同じく、次のような設定ファイルを作っているとします。
{
"string_value": "hoge",
"int_value": 123,
"array_value": [
"fuga",
"piyo"
],
"nest": {
"nested_value": "nested"
}
}
書式
--CONFIG:FILE-NAME.KEY=CUSTOM-VALUE
書き方の例
vapor run --config:settings.string_value=foo
使い方
使い方は前述の方法と同じです。
drop.config["setting", "string_value"]?.string // Optional("foo")
前述の通り、設定ファイルの設定よりもコマンドラインでの設定の方が優先度が高いので、foo
という値に上書きされます。
その他補足
▶︎ 設定値を変えた時のアプリケーションのビルドについて
- jsonファイルの設定値を変更してもアプリケーションを再度ビルドし直す必要はない。
- また、アプリケーションの実行中にjsonファイルを変更しても、設定値の読み込み処理さえ走れば変更した値が読まれる
▶︎ Dropletを使わない場合
これまでの例では、Droplet
クラスを使用して、Dropletを介して設定値を取得していました。
通常はそのような形で取得すればいいかと思いますが、Dropletを使わない方法も紹介します。
#if os(Linux)
let workingDirectory = "./"
#else
let workingDirectory: String = {
let parent = #file.characters.split(separator: "/").map(String.init).dropLast().joined(separator: "/")
let path = "/\(parent)/../"
return path
}()
#endif
let config = try Config(prioritized: [.directory(root: workingDirectory + "Config/")])
config["server", "http", "host"]?.string // Optional("0.0.0.0")
こちらは、Vaporのサンプルコードの一つのSlack botのコードにて書かれている書き方になります。
Config
構造体を使っています。
DropletもこのConfig構造体をプロパティーとして持っているだけなので、やっていること自体は同じですね。
▶︎ 設定値を取得する別の書き方
これまで紹介した書き方は次のようなものでした。
drop.config["server", "http", "host"]?.string
前述の記述以外に下のような書き方もできます。
設定値のキーまでのパスをarrayで渡す
let pathIndex = ["server", "http", "host"]
drop.config[pathIndex]?.string
まあ、この書き方はあまりメリット無いかもしれないですね。
ドット区切りの文字列でキーまでのパスを指定する
drop.config[path: "server.http.host"]?.string
これらは、PathIndexable
というパッケージとしてVaporの中に組み込まれているので、実装はこちらのリポジトリをご確認ください。
https://github.com/vapor/path-indexable