RustでRocketを使ってAPIを作ってみる
なんとなくの前回の続きで、だいたい自分用メモです。
ohshige.hatenablog.com
RustでAPIを実現するためのフレームワークはいくつかあるようですが、今回はRocketを使います。
基本的にはチュートリアルの通りにやっています。
rocket.rs
やりたいことは前回作ったDBからデータを取得するメソッドをAPI化して、JSONを返却するようにするというものです。
以降は、rustc 1.42.0-nightly
で動作確認済みです。
Cargo.toml
[package] name = "demo" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] rusqlite = "*" rocket = "*" rocket_contrib = { version = "*", features = ["json"] } serde = "*" serde_derive = "*"
main.rs
#![feature(proc_macro_hygiene, decl_macro)] #[macro_use] extern crate rocket; #[macro_use] extern crate serde_derive; extern crate rusqlite; extern crate rocket_contrib; use rusqlite::{Connection, NO_PARAMS}; use rocket_contrib::json::Json; #[derive(Debug, Serialize)] struct User { user_id: usize, name: String, } #[get("/users")] fn get_users() -> Json<Vec<User>> { let conn = Connection::open("my.db").unwrap(); let mut stmt = conn.prepare(" SELECT user_id, name FROM users ORDER BY user_id ASC ", ).unwrap(); let users = stmt.query_map(NO_PARAMS, |row| { Ok(User { user_id: row.get::<_, i64>(0).unwrap() as usize, name: row.get::<_, String>(1).unwrap(), }) }).unwrap(); let mut result: Vec<User> = vec![]; for user in users { result.push(user.unwrap()); } Json(result) } #[get("/users/<user_id>")] fn get_user(user_id: usize) -> Option<Json<User>> { let conn = Connection::open("my.db").unwrap(); let mut stmt = conn.prepare(" SELECT user_id, name FROM users WHERE user_id = ? ", ).unwrap(); let id = user_id as i64; let mut users = stmt.query_map(&[&id], |row| { Ok(User { user_id: row.get::<_, i64>(0).unwrap() as usize, name: row.get::<_, String>(1).unwrap(), }) }).unwrap(); let user = users.next(); match user { Some(user) => Some(Json(user.unwrap())), None => None, } } fn main() { rocket::ignite().mount("/", routes![get_users, get_user]).launch(); }
メインの処理はほぼ変わっておらず、User構造体をシリアライズ可能にしたのとレスポンスをJSONにしたくらいです。
上記を実行すると以下のようになります。
$ cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.09s Running `target/debug/demo` 🔧 Configured for development. => address: localhost => port: 8000 => log: normal => workers: 32 => secret key: generated => limits: forms = 32KiB => keep-alive: 5s => tls: disabled 🛰 Mounting /: => GET /users (get_users) => GET /users/<user_id> (get_user) 🚀 Rocket has launched from http://localhost:8000
curlで確認してみると、問題なく動いています。
$ curl http://localhost:8000/users [{"user_id":1,"name":"田中太郎"},{"user_id":2,"name":"鈴木次郎"}] $ curl http://localhost:8000/users/1 {"user_id":1,"name":"田中太郎"} $ curl http://localhost:8000/users/999 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>404 Not Found</title> </head> <body align="center"> <div align="center"> <h1>404: Not Found</h1> <p>The requested resource could not be found.</p> <hr /> <small>Rocket</small> </div> </body> </html>
現状だと、存在しないユーザIDを指定した場合でも404は返りますが、デフォルトのままHTMLになってしまっているので、しっかりやるならエラーハンドリングが必要です。