リクエストはバックエンドで何になるか
バックエンドとは、Web アドレスの裏にあって、リクエストに答えるプログラムです。リクエストを読み、どのコードの仕事かを決め、中身を確かめ、データに問い合わせ、答えを返します。
どの言語で書かれていても、バックエンドはこの5つの仕事をします。このレッスンでは、その様子を見ます。
このレッスンのゴール
メモ
バックエンドがリクエストに何をするかを順に言い、データベースへの問い合わせを示せる。
重要な言葉
| ことば | いみ |
|---|---|
| バックエンド | アドレスの裏でリクエストに答えるプログラム |
| ルート | リクエストを、扱うコードへ送る決まり |
| ハンドラー | 1種類のリクエストに答えるコード |
| クエリ文字列 | アドレスの疑問符より後ろの部分 |
| パラメーター | SQL の文とは別に、データベースへ送る値 |
| レスポンス | バックエンドが返す、ステータス、ヘッダー、本文 |
学生が入力するセルは、このプレビューでは空白です。
リクエストからレスポンスまでの5段階
まずバックエンドは、リクエストを読み取ります。メソッド、パス、クエリ文字列です。次にルートを決め、どのハンドラーのものかを決めます。
ハンドラーは、リクエストを確かめ、データに問い合わせ、ステータスと本文で答えます。ラボのバックエンドは PostgREST というプログラムで、ルートは表です。問い合わせる表を作りましょう。
psql にパスワードを渡す
export PGPASSWORD=shopここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
books 表を作る
psql -h db -U shop -c "drop table if exists books; create table books (id serial primary key, title text not null, year int not null, available boolean not null default true); insert into books (title, year, available) values ('海の地図', 1998, true), ('ヨーロッパの川', 2004, false), ('夜行列車', 2011, true); notify pgrst, 'reload schema'"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
存在しない列を問い合わせる
curl -s -w "\n" "http://api:3000/books?nope=eq.1"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
バックエンドは問い合わせる前に確かめる
答えは、nope という列はない、と言い、400 と理由を付けています。コード 42703 は PostgreSQL 自身のものなので、ここでは、悪い名前を見つけたのはデータベースです。
念入りなバックエンドは、名前を先に確かめてから、データに問い合わせます。動かないリクエストはすぐ断られ、悪いリクエストはデータに届きません。課題は、この作り方をします。
クエリ文字列はリクエストの質問
アドレス /books?available=eq.true&select=title&order=id は、3つのことを言っています。available が true の行だけを残す。title の列だけを返す。id の順に並べる。
送ってみて、同じ質問を自分で SQL でデータベースにもしてみましょう。
リクエストを送る
curl -s -w "\n" "http://api:3000/books?available=eq.true&select=title&order=id"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
同じ質問をデータベースにする
psql -h db -U shop -At -c "select title from books where available = true order by id"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
バックエンドの問い合わせを見る
その SQL は、バックエンドが書きました。見るには、PostgreSQL が受け取るすべての文をログに残させ、ラボの docker logs で読みます。この設定はこのレッスンだけのもので、最後の Run で戻します。
docker logs が使えるのは、Docker コマンドのあるラボだけです。
文のログを有効にする
psql -h db -U shop -c "alter system set log_statement = 'all'" -c "select pg_reload_conf()"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
同じリクエストをもう一度送る
curl -s -o /dev/null "http://api:3000/books?available=eq.true&select=title&order=id"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
バックエンドが送った SQL を読む
docker logs --tail 30 db 2>&1 | grep -o 'SELECT "public"."books"[^)]*' | tail -1ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例: リクエストの部分と SQL の部分
| リクエストの部分 | 何を頼むか | 送られた SQL |
|---|---|---|
| /books | books 表 | FROM "public"."books" |
| available=eq.true | available が true の行だけ | WHERE "public"."books"."available" = $1 |
| select=title | title の列だけ | SELECT "public"."books"."title" |
| order=id | id の順 | ORDER BY "public"."books"."id" |
学生が入力するセルは、このプレビューでは空白です。
別に送られた値を読む
docker logs --tail 30 db 2>&1 | grep -o 'parameters: .*' | tail -1ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
値は SQL とは別に届く
SQL には = $1 と書いてあります。値の t、つまり true は別に送られたので、データベースはそれをデータとして扱い、SQL としては扱いません。だから、リクエストはクエリを書き換えられません。
確かめましょう。攻撃のように見えるタイトルを送って、バックエンドがどうするかを見ます。
SQL に見えるタイトルを送る
curl -s -G --data-urlencode "title=eq.x'; drop table books; --" -w "\n" "http://api:3000/books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
どう渡されたかを見る
docker logs --tail 30 db 2>&1 | grep -o 'parameters: .*' | tail -1ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
本の数を数える
psql -h db -U shop -At -c "select count(*) from books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
文のログをまた止める
psql -h db -U shop -c "alter system reset log_statement" -c "select pg_reload_conf()"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
よくある間違い
注意
バックエンドは、ブラウザーとデータベースをつなぐ管にすぎないと考える人がいます。バックエンドは、確かめ、決め、制限します。一致なしは、中身が空の 200 で、悪いリクエストは 400 です。その区別は、バックエンドがします。
さらに: もっと大きな質問
同じ形で、次の質問のリクエストを書きます。2000年より後に出た、貸出できる本を、新しい順に、title と year だけで。curl で送ります。
そのあと、期待する SQL を書き、ログを読んで確かめましょう。