この記事は セゾン情報システムズ Advent Calendar 2020 8日目の記事です。
あらすじ
- https://qiita.com/Yoshihiro-Hirose/items/982429f74b2900963533 で Rust を始めてみた
- 今回は REST API サーバを作っていきたい(途中まで)
actix-web
- actix-web を使って実装していきます
- https://actix.rs/
- https://crates.io/crates/actix-web
Web サーバの hello, world
-
適当なディレクトリでコマンドプロンプト起動
-
cargo new web_hello
を実行 -
web_hello をディレクトリを vscode で開く
-
Cargo.toml ファイルを開き、dependencies に
actix-web = "3.3.2"
を追加 -
以下コードを main.rs に貼り付け
use actix_web::{get, web, App, HttpServer, Responder}; #[get("/{id}/{name}/index.html")] async fn index(web::Path((id, name)): web::Path<(u32, String)>) -> impl Responder { format!("Hello {}! id:{}", name, id) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| App::new().service(index)) .bind("127.0.0.1:8080")? .run() .await }
-
cargo run
を実行 -
ブラウザを開き
http://127.0.0.1:8080/123/namae/index.html
にアクセスする -
id と name が返される
※ URL のパスを動的に取得できることが確認できます
※ 関数に #[get
がついていますが GET であることを表しています
TODO 管理
TODO を取得、登録する API の雛形を作っていきます
全体コードは最後に載せます
crate の追加
json を扱うので関連する crate を追加します
[dependencies]
actix-web = "3.3.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
構造体の定義
TODO の構造体を定義し、GET と POST で利用します。
新規登録時は id を自動生成したいので未指定を許容したく Option としています。
#[derive(Debug, Serialize, Deserialize)]
struct Todo {
id: Option<u32>,
content: String,
done: bool,
}
TODO の取得(GET)
構造体を json として返します。
ここで取得した ID を使ってデータベースなどにアクセスする予定です。
#[get("/todos/{id}")]
async fn get_todo(web::Path(id): web::Path<u32>) -> impl Responder {
println!("get_todo");
let id_option: Option<u32> = Some(id);
HttpResponse::Ok().json(Todo {
id: id_option,
content: String::from("やること"),
done: false,
})
}
TODO の登録(POST)
JSON をリクエストで受け取り、構造体に変換して扱います。
#[post("/todos")]
async fn post_todo(todo: web::Json<Todo>) -> impl Responder {
println!("post_todo");
println!("{:?}", todo);
HttpResponse::Ok().body("ok")
}
コード全体
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Todo {
id: Option<u32>,
content: String,
done: bool,
}
#[get("/todos/{id}")]
async fn get_todo(web::Path(id): web::Path<u32>) -> impl Responder {
println!("get_todo");
let id_option: Option<u32> = Some(id);
HttpResponse::Ok().json(Todo {
id: id_option,
content: String::from("やること"),
done: false,
})
}
#[post("/todos")]
async fn post_todo(todo: web::Json<Todo>) -> impl Responder {
println!("post_todo");
println!("{:?}", todo);
HttpResponse::Ok().body("ok")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(get_todo).service(post_todo))
.bind("127.0.0.1:8080")?
.run()
.await
}
サーバ起動
cargo run
を実行
ブラウザで http://localhost:8080/todos/123
にアクセスする → json が返される
HTTPクライアントなどで http://localhost:8080/todos
に以下を POST する → サーバのコンソールに表示される
{
"content": "なにかやる",
"done": false
}
まとめ
思ったよりも少ないコードでサーバが書けそうでした
今後は Web アプリケーションや WebAssembly なども触っていきたいと思います。
明日の セゾン情報システムズ Advent Calendar 2020 もお楽しみに!