RustでAPIサーバーを立てる練習をしましょう。
動機は「Rustですか? 少しは使えますけど……」と答えてみたいからです。
どうしてAPIサーバーか。
他のプログラムを作ったときに、組み合わせやすいからです。
というわけで、axum
を導入するところから始めます。
ドキュメントの例示コードを動かすところから始めます。
パッケージのインストール
Cargo.toml
は以下を参照し、必要なパッケージをインストールします。
cargo add axum
みたいな感じで、ひとまずコマンドラインから追加しました。
例示とはバージョンがずれると思うので動かない可能性がありますから、後で随時直します。
cargo new test-api-server
cd test-api-server
cargo add axum
...
[package]
name = "test-api-server"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.7.9"
serde = "1.0.216"
tokio = "1.42.0"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
ソースコードのコピペ
ソースコードを以下からコピペします。
動作確認
cargo run
動かすと、コンパイル段階でエラーになります。
そりゃそうですね。
エラーメッセージから検討をつけると、features関連っぽいので、exampleを参考にして、featuresフラグを付加します。
- serde = "1.0.216"
+ serde = { version = "1.0.216", features = ["derive"] }
- tokio = "1.42.0"
+ tokio = { version = "1.42.0", features = ["full"] }
もう一度動かしてみます。
...
Compiling test-api-server v0.1.0 (E:\test-api-server)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.03s
Running `target\debug\test-api-server.exe`
こんな感じのログになりましたので、APIサーバーが立ちあがったようです。
確認してみましょう。
リクエストを送信してみるテスト
VSCodeへ上記の拡張機能を追加し、request.http
というファイルを作成します。
GET http://127.0.0.1:3000
そして、上記の記載の上に表示された「Send Request」をクリックして、以下のレスポンスが表示されればOKです。
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
content-length: 13
connection: close
date: Mon, 23 Dec 2024 09:55:08 GMT
Hello, World!
さらにPOSTもテストします。
request.http
へ###
で区切って、リクエストを追加します。
GET http://127.0.0.1:3000
###
POST http://127.0.0.1:3000/users
Content-Type: application/json
{
"username": "Alice"
}
これを同様に実行して、以下のようになればPOST側もOKです。
HTTP/1.1 201 Created
content-type: application/json
content-length: 30
connection: close
date: Mon, 23 Dec 2024 09:57:20 GMT
{
"id": 1337,
"usern1ame": "Alice"
}
ほぼコピペしかしていませんが、無事APIサーバーが立ちました。
それから、ついでにビンゴカードを生成する
これだけではつまらないため、何かしてみます。
少し考えた末、別の記事で作ったのと同じ、ビンゴカードを生成するエンドポイントをつくることにしました。
let app = Router::new()
.route("/", get(root))
.route("/users", post(create_user))
.route("/cards", get(create_cards));
/cards
エンドポイントを作成します。
create_card
はそれっぽく書きます。
async fn create_cards() -> impl IntoResponse{
let mut cards: Vec<Vec<u8>> = Vec::new();
let mut rng = rand::thread_rng();
let mut fy = FisherYates::default();
for n in 0..5 {
let mut tmp: Vec<u8> = (n*15..n*15+15).collect();
let _ = fy.shuffle(&mut tmp, &mut rng);
cards.push(tmp[0..5].to_vec());
}
(StatusCode::CREATED, Json(cards))
}
シャッフル処理は以下を参照しました。
shuffleの第2引数は乱数生成器を入れるイメージでしょうか。
これで、以下のようなレスポンスが得られました。
HTTP/1.1 201 Created
content-type: application/json
content-length: 83
connection: close
date: Mon, 23 Dec 2024 10:54:11 GMT
[
[
8,
7,
13,
12,
4
],
[
19,
20,
18,
21,
24
],
[
43,
44,
37,
32,
33
],
[
45,
54,
52,
57,
49
],
[
66,
74,
72,
65,
68
]
]
終わりに
これで基本的なAPIサーバーの立ち上げ方がわかりました。
実際に複雑な処理をしようとすると、Rustの勉強不足で挫折しそうなので、まずは小さなステップを踏めたところで満足しています。
ここまで読んでいただきありがとうございました。