Rocketでデータベース設定を環境によって切り替える
設定ファイルと環境変数
ここに書いてありますが、Rocket は Rocket.toml というファイルで設定を管理できます。また、環境変数もROCKET_xxxx
という形式にすることで、Rocket.toml の値を上書きすることができます。そして、環境変数にROCKET_PROFILE=dev
などとすることで、プロフィールに該当する設定が有効になります。また、この設定ファイルと環境変数の仕組みはFigmentというライブラリをベースに作られています。
Rocket.toml
Rocket.toml は下記のような感じで設定できます。[default]
とか[local]
とかがプロフィールです。default
は全プロフィールで適用されるデフォルト値です。下記の場合、local
とprod
というプロフィールがあり、どちらのプロフィールでもaddress
とlimits
は同じということになります。hoge
とdatabase.hoge
については、プロフィール毎に異なります。
[default]
address = "0.0.0.0"
limits = { form = "64 kB", json = "1 MiB" }
[local]
hoge = "local hoge"
[local.databases.hoge]
url = "postgres://user:password@localhost/hoge"
[prod]
hoge = "prod hoge"
[prod.databases.hoge]
url = "postgres://user:password@prod/hoge"
環境変数
.env などで下記のように環境変数を設定することで、上記の Rocket.toml を上書きできます。
ROCKET_PROFILE=dev
ROCKET_HOGE="env hoge"
ROCKET_DATABASES={hoge={url=postgres://user:password@env/hoge}}
上記で、ROCKET_DATABASES_HOGE_URL=postgres://user:password@env/hoge
といったような設定方法は、試してみたけどできなそうでした。データベースが複数ある場合などは、結構煩雑になるかもしれません。
main.rs で取得してみる
#[macro_use] extern crate rocket;
use rocket::Config;
use serde::Deserialize;
use dotenv::dotenv;
use rocket::figment::value::Map;
#[derive(Deserialize, Debug)]
struct MyConfig {
hoge: String,
databases: Map<String, Map<String, String>>
}
#[get("/")]
fn index() -> String {
let config = Config::figment().extract::<MyConfig>();
format!("{:?}", config)
}
#[launch]
fn rocket() -> _ {
dotenv().ok();
rocket::build()
.mount("/", routes![index])
}
レスポンスは下記のようになります。
Ok(MyConfig { hoge: "env hoge", databases: {"hoge": {"url": "postgres://user:password@env/hoge"}} })
コードで設定値を使う
下記のような感じで、rocket::build().attach(AdHoc::config::<AppConfig>())
とやると、ハンドラ関数内で使えるようになりました。便利な気がします。まあ、dotenv とか使うだけでもいい気もします。ハンドラ関数から usecase -> repository に必要となる設定値・DB Pool などを全部渡すような形になると、渡すのがめんどくさいというのは結構大きな問題としてあるのですが、まあ確かに、usecase, repository で色々考えなくて済むというのもあるかなーと思いました。せっかく Rocket はハンドラ関数の引数に設定するところまでは、超簡単にできるようになっているので、それを使って、usecase -> repository には順番に渡していこうかなと思っております。
#[macro_use] extern crate rocket;
use serde::Deserialize;
use dotenv::dotenv;
use rocket::figment::value::Map;
use rocket::{State, fairing::AdHoc};
#[derive(Deserialize, Debug)]
struct AppConfig {
hoge: String,
databases: Map<String, Map<String, String>>
}
#[get("/")]
fn index(config: &State<AppConfig>) -> String {
config.databases.get("hoge").unwrap().get("url").unwrap().to_string()
}
#[launch]
fn rocket() -> _ {
dotenv().ok();
rocket::build()
.mount("/", routes![index])
.attach(AdHoc::config::<AppConfig>())
}
Discussion