🐤

Windows 11でPostgRESTを動かしてみる

2022/12/31に公開

はじめに

Windows 11でPostgRESTのチュートリアルを試してみました。

PostgRESTとは

PostgRESTとは、PostgreSQLデータベースを操作するRESTful APIを提供するWebサーバーです。ざっくりまとめると、以下の3ステップでデータベースにアクセスできるAPIが生成されます。

  1. PostgreSQLデータベースの実行環境を用意
  2. PostgRESTの設定ファイルにデータベースの接続先等を記述
  3. PostgRESTを起動

今回の実行環境

  • OSはWindows 11
  • PostgreSQL 14をインストール済み
  • Docker Desktopをインストール済み
  • WSL2をインストール済み
  • Git Bashをインストール済み

手順(Tutorial 0)

公式ドキュメントのTutorial 0 - Get it Runningの手順に沿って実施していきます。

PostgreSQLを動かすDockerコンテナを作成

Windows PowerShellなどのターミナルで、以下のコマンドを実行し、PostgreSQL入りのDockerコンテナを作成します。

docker run --name tutorial -p 5433:5432 -e POSTGRES_PASSWORD=password -d postgres

Docker Desktopのコンテナ一覧にこんな感じで生成されていれば良いです。

システム環境変数のPathにPostgreSQLのパスを追加

Windowsの環境変数の設定画面を開く

システム環境変数のPathに、あらかじめWindowsにインストールしておいたPostgreSQLのbinフォルダのパスを追加
(C:\Program Files\PostgreSQL\14\bin とかになると思います)

PostgRESTをダウンロード

PostgRESTのGitHubリポジトリから、最新のPostgRESTをダウンロードします。
(今回は postgrest-v10.1.1-windows.x64.zip にします)

ダウンロードしたzipファイルを解凍しておいてください。

Dockerコンテナ内のPostgreSQLにスキーマを作成

先程の手順で作成したDockerコンテナに接続し、今回使用するスキーマを作成していきます。
まずは以下のコマンドでコンテナに接続します。

docker container exec -it tutorial /bin/bash

コンテナに接続できたら、続けてその中のPostgreSQLに接続します。

psql -U postgres

スキーマを作成します。

create schema api;

todosテーブルを作成します。

create table api.todos (
  id serial primary key,
  done boolean not null default false,
  task text not null,
  due timestamptz
);

todosテーブルにデータを追加します。

insert into api.todos (task) values
  ('finish tutorial 0'), ('pat self on back');

web_anonロールを作成します。

create role web_anon nologin;

web_anonロールにapiスキーマへのusage権限を追加します。

grant usage on schema api to web_anon;

web_anonロールにtodosテーブルへのselect権限を追加します。

grant select on api.todos to web_anon;

PostgRESTからのログインに使用するauthenticatorロールを作成し、web_anonロールと同様の権限を付与します。

create role authenticator noinherit login password 'password';
grant web_anon to authenticator;

これでスキーマの準備は一旦完了です。

PostgRESTの設定ファイルを作成

先程ダウンロードしたPostgRESTのzipファイルを解凍すると、中にpostgrest.exeが入っていると思います。
そのフォルダと同じ場所に、tutorial.confを作成します。

ファイルの中身は以下のようにしてください。

db-uri = "postgres://authenticator:password@localhost:5433/postgres"
db-schemas = "api"
db-anon-role = "web_anon"

PostgRESTを起動

Windows PowerShellでpostgrest.exeが置いてあるフォルダに移動し、exeを起動します。

.\postgrest.exe tutorial.conf

こんな内容の起動ログが出力されたら成功です。

30/Dec/2022:22:02:50 +0900: Attempting to connect to the database...
30/Dec/2022:22:02:50 +0900: Connection successful
30/Dec/2022:22:02:50 +0900: Listening on port 3000
30/Dec/2022:22:02:50 +0900: Listening for notifications on the pgrst channel
30/Dec/2022:22:02:50 +0900: Config reloaded
30/Dec/2022:22:02:50 +0900: Schema cache loaded

この状態で http://localhost:3000/todos にアクセスすると、以下のようなjsonデータが出力されると思います。

[
  {
    "id": 1,
    "done": false,
    "task": "finish tutorial 0",
    "due": null
  },
  {
    "id": 2,
    "done": false,
    "task": "pat self on back",
    "due": null
  }
]

ここまでで、公式ドキュメントのTutorial 0 - Get it Runningの実施は完了です。

手順(Tutorial 1)

ここからは、Tutorial 1 - The Golden Keyの内容に沿って進めていきます。

todosテーブルを更新するためのロールを作成

コンテナ内のPostgreSQLに接続

docker container exec -it tutorial /bin/bash
psql -U postgres

todo_userロールを作成します。

create role todo_user nologin;
grant todo_user to authenticator;

todosテーブルで使用される全ての権限をtodo_userに付与します。

grant usage on schema api to todo_user;
grant all on api.todos to todo_user;
grant usage, select on sequence api.todos_id_seq to todo_user;

シークレットキーを生成

Git Bashを起動し、以下のコマンドを実行します。

export LC_CTYPE=C
< /dev/urandom tr -dc A-Za-z0-9 | head -c32

(※先頭の < を省略しないように注意)

出力された32文字の文字列をコピーしておきます。
次に、tutorial.confをエディタで開き、以下の1行を追記します。

jwt-secret = "ここに生成したシークレットキー"

追記後、postgrest.exeを再起動しておいてください。

シークレットキーからアクセストークンを生成

JSON Web Tokens - jwt.ioにアクセスし、PAYLOADとVERIFY SIGNATUREを以下のように設定してください。

設定後、左側のEncodedに表示された文字列をコピーしておいてください。
これがAPIのアクセストークンになります。

API経由でtodoテーブルにレコードを追加してみる

Git Bashを起動し、以下のコマンドを実行していきます。

直前の手順でコピーしたトークンを変数に設定します。

export TOKEN=ここにトークンを貼り付け

API経由でtodosテーブルにレコードを登録してみます。

curl http://localhost:3000/todos -X POST \
     -H "Authorization: Bearer $TOKEN"   \
     -H "Content-Type: application/json" \
     -d '{"task": "learn how to auth"}'

todosテーブルの全レコードのdoneカラムの値をtrueに更新する処理を実行してみます。

curl http://localhost:3000/todos -X PATCH \
     -H "Authorization: Bearer $TOKEN"    \
     -H "Content-Type: application/json"  \
     -d '{"done": true}'

todosテーブルのレコードを取得してみます。

curl http://localhost:3000/todos

こんなjsonデータが出力されていれば成功です。

[{"id":1,"done":true,"task":"finish tutorial 0","due":null},
 {"id":2,"done":true,"task":"pat self on back","due":null},
 {"id":3,"done":true,"task":"learn how to auth","due":null}]

トークンに有効期限を持たせてみる

5分後に有効期限切れになるトークンを作成してみます。
まずはDockerのPostgreSQLに接続し、以下のSQLを実行します。

select extract(epoch from now() + '5 minutes'::interval) :: integer;

実行結果の数値をコピーしておいてください。

JSON Web Tokens - jwt.ioにアクセスし、PAYLOADを以下のように編集します。

VERIFY SIGNATUREには前の手順と同様の文字列を設定しておきます。
その後、左側のEncodedに表示された文字列をコピーしておいてください。

次に、Git Bashで、以下のコマンドを実行していきます。

export NEW_TOKEN=ここにトークンを貼り付け

todosテーブルの中身を取得してみます。

curl http://localhost:3000/todos \
  -H "Authorization: Bearer $NEW_TOKEN"

select extract~ のSQLを実行してから5分以内であれば、todosテーブルの中身が表示されます。
5分以上経過した状態で上記のAPIを呼び出すと、以下のレスポンスが返ってきます。

{"code":"PGRST301","details":null,"hint":null,"message":"JWT expired"}

トークンを即時失効させてみる(特定のユーザーからのアクセスを拒否する)

JSON Web Tokens - jwt.ioにアクセスし、PAYLOADを以下のように編集します。

VERIFY SIGNATUREには前の手順と同様の文字列を設定しておきます。
その後、左側のEncodedに表示された文字列をコピーしておいてください。

DockerのPostgreSQLに接続し、以下のSQLを実行してユーザー認証用のスキーマと関数を作成します。

create schema auth;
grant usage on schema auth to web_anon, todo_user;

create or replace function auth.check_token() returns void
  language plpgsql
  as $$
begin
  if current_setting('request.jwt.claims', true)::json->>'email' =
     'disgruntled@mycompany.com' then
    raise insufficient_privilege
      using hint = 'Nope, we are on to you';
  end if;
end
$$;

エディタでtutorial.confを開き、以下の行を追記します。

db-pre-request = "auth.check_token"

追加後、postgrestを再起動します。

Git Bashで、以下のコマンドを実行してtodosテーブルを更新してみます。

curl http://localhost:3000/todos -X PATCH \
  -H "Authorization: Bearer $TOKEN"    \
  -H "Content-Type: application/json"  \
  -d '{"done": true}'

これは問題なく実行されます。

次に、アクセス拒否したいメールアドレス(disgruntled@mycompany.com)を含むトークンを使ってAPIにアクセスしてみます。

curl http://localhost:3000/todos -X PATCH      \
  -H "Authorization: Bearer $WAYWARD_TOKEN" \
  -H "Content-Type: application/json"       \
  -d '{"task": "AAAHHHH!", "done": false}'

以下のレスポンスが返ってきます。また、todosテーブルのレコードは更新されません。

{"code":"42501","details":null,"hint":"Nope, we are on to you","message":"insufficient_privilege"}

これで、公式ドキュメントのTutorial 1 - The Golden Keyの実施も完了です。

おわりに

Windows 11でPostgRESTを動かしてみました。
この記事ではチュートリアルの内容しか紹介していませんので、詳細な使い方については公式ドキュメントをご参照ください。

Discussion