Rustを勉強するためにactix-webを使ってwebアプリを書いてみた備忘録。
今日やったこと
Rust初心者で何も分からないので、actix-web と diesel のGetting Startedを読みながら、雰囲気でコードを書いてみた。
diesel_cli のインストール
DBの作成・マイグレーションなどをするため、cliをインストールする必要がある。
$ cargo install diesel_cli
で普通にインストールできた。 もし postgresql とかがローカルになければ、sqlite だけのインストールもできるらしい。
$ cargo install diesel_cli --no-default-features --features sqlite
DBの作成
DATABASE_URLを指定して diesel setup
するとDBが作れる。
$ DATABASE_URL=development.sqlite3 diesel setup
毎回指定するのも面倒なので、.envrc に入れておく。
$ echo export DATABASE_URL=development.sqlite3 > .envrc
マイグレーションファイルの作成
diesel migration generate
で作成できる。
$ diesel migration generate create_posts Creating migrations/2019-10-27-152149_create_posts/up.sql Creating migrations/2019-10-27-152149_create_posts/down.sql
ActiveRecordみたいにRubyではなくて、生SQLだった。この潔さは嫌いじゃない。
DBのマイグレーション
diesel migration run
でマイグレーションを実行してくれる。
$ diesel migration run Running migration 2019-10-27-152149_create_posts
diesel migration redo
で down.sql の動作確認もできる。
DBの接続
こんな感じで connection を作る。
pub fn establish_connection() -> SqliteConnection { let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); SqliteConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url)) }
コネクションの管理を diesel でやっているのか、自分でやる必要あるのかはよく分かっていない。
複数のPostを取得する
こんな感じでfilterやlimitが書けるらしい。たぶんorderとかも使える気がする。
let results = posts .filter(published.eq(true)) .limit(5) .load::<Post>(&connection) .expect("Error loading posts");
1つのPostを取得する
findのあとにfirstを書くのが冗長感あるけど、たぶん posts.find(id)
がWHERE句になるんだと思う。
let post = posts.find(id) .first::<Post>(&connection) .expect("Error finding posts");
Postを登録する
insert_intoを使う。
ちなみにdieselのGetting Started だとget_resultを使っているけど、sqliteは対応してないので代わりにexecuteを使っている。
let new_post = NewPost { title: "title", body: "body", }; let connection = establish_connection(); diesel::insert_into(posts::table) .values(&new_post) .execute(&connection) .expect("Error saving new post");
Postを更新する
Getting Startedを参考にして書いたら、普通に動いた。
diesel::update(posts.find(id)) .set(published.eq(true)) .execute(&connection) .expect(&format!("Unable to find post {}", id));
Postを削除する
これもドキュメント通り。
diesel::delete(posts.find(id)) .execute(&connection) .expect("Error deleting posts");
ルーティング周り
それっぽく書いたら、動いた。
HttpServer::new(|| { App::new() .route("/", web::get().to(index)) .route("/posts", web::get().to(posts_index)) .route("/posts/{id}", web::get().to(posts_show)) .route("/posts", web::post().to(posts_create)) .route("/posts/{id}", web::put().to(posts_update)) .route("/posts/{id}", web::patch().to(posts_update)) .route("/posts/{id}", web::delete().to(posts_destroy)) })