JWT token の勉強をしていて、Redis で token を管理しているという話を教えてもらったので Redis を使うだけの環境を作ってみていました。
Docker で環境を構築します
構成
/ |- /api (express) | |- Dockerfile |- /redis |- docker-compose.yml
docker-compose.yml
version: '3' services: redis: image: redis:latest volumes: - ./redis/data:/data ports: - 6379:6379 api: build: context: './api' dockerfile: 'Dockerfile' volumes: - ./api:/api - ./api/package.json:/api/package.json - ./api/package-lock.json:/api/package-lock.json - ./api/node_modules:/api/node_modules ports: - 3000:3000 depends_on: - redis tty: true working_dir: "/api" command: bash -c "npm run start"
/api/Dockerfile
FROM node:12.18.0 WORKDIR /api
build
$ docker-compose build $ docker-compose up
redis と api のコンテナが動いてたらOK
今回はモックのAPIなので redis 特に設定せずに使います。(production で使う場合は config を作って読み込ませるとか必要な気がします)
これくらいだとMacでも速いですね。
ioredis で api から Redis に接続する
apiディレクトリに移動してパッケージをインストールします。
$ npm install express ioredis
開発環境なら nodemon
を入れて "start": "nodemon ./index.js"
とかとしておくと楽です。
api/index.js
const express = require('express'); const app = express(); const PORT = 3000; // Router const authRouter = require('./routes/auth'); // Middleware // Express v4.16.0 から core に戻ったみたいなので Body-Parser をインストールしなくてもOK app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Routing middleware app.use('/api/user', authRouter); app.listen(PORT, () => console.log(`SERVER started on localhost:${PORT}`));
./routes/auth.js
const router = require('express').Router(); const Redis = require('ioredis'); const redis = new Redis(6379, 'redis'); router.post('/login', async (req, res) => { // Moc user const user = {id:1, name: '星宮いちご'} // ID を key に String 型でデータを保存 'EX', time (second) で有効期限を設定できる await redis.set(user.id, JSON.stringify(user), 'EX', 60) return res.send(user); }); router.get('/posts', async (req, res) => { const userID = req.body.id; try { // redis から データを取得 const data = await redis.get(userID); // redis 上に存在してなかった場合 err ではなく null が返される if (!data) { throw new Error('Access Denied.'); } return res.send(JSON.parse(data)); } catch (err) { return res.status(400).send(err.message); } }); module.exports = router;
セキュリティとか何もない感じですが、docker-compose up
して、localhost:3000/api/users/login
に POST でアクセスすると user データが Redis に保存されます。その後に localhost:3000/api/users/posts
に {id: 1}
を持たせてアクセスすると Redis のデータが有効期限内なら user データが返され、期限切れだと Access Denied.
が返るようになっているかと思います。
Redis のデータの確認
docker のコンテナに入って redis-cli を使って確認します。
$ docker exec -it <Redis_container_name> bash $ redis-cli
# 登録されているキーの確認 127.0.0.1:6379> keys * # キーの値を確認 (String 型) 127.0.0.1:6379> get key # キーの有効期限を確認 127.0.0.1:6379> ttl key # キーを削除 127.0.0.1:6379> del key # データを作成 (String型) 127.0.0.1:6379> set key value # キーに有効期限を設定 127.0.0.1:6379> expire key time
ほぼ ioredis からのコマンドと同じで redis の確認・操作をすることができました。
有効期限の設定付きでデータを作成する場合 ioredis では redis.set(key, value, 'EX', time)
で丸っと作成することができましたが、redis で直接データをつくる際に set key value 'EX' time
とすると、EX: time
というデータが作られてしまいます。有効期限の設定は別途 expire
コマンドで設定する必要がありました。
redis に入ってテキトーなキーで値を作成すると、作成したキーを id にしてlocalhost:3000/api/users/posts
にアクセスすると保存した値が返されます。(JSON.parse
がエラーにならなければ)
所感
別に express でなくても良かったと思いますが、ioredis を使うと簡単に JavaScript (node.js) で Redis を使うことができました。
1点だけポイントとしては、new Redis()
のに渡しているポートの設定ですが docker の場合 Redis port, Redis host を docker-compose のport番号, コンテナ名 で指定する必要がありました。
config を作れば、コンテナ名でなくポート番号で指定できるようになるのかもしれません。
JWT の実験や Redis で List 型や Hash 型の操作もしてみたので、それは追々メモ書いていきたいと思います。
おわり。
[参考]
- GitHub - luin/ioredis: 🚀 A robust, performance-focused and full-featured Redis client for Node.js.
- 入門 : Redis のデータ構造と概念 — Redis Documentation (Japanese Translation)
- redisドキュメント日本語訳 — redis 2.0.3 documentation
ioredis で使えるコマンドはだいたいココに載ってるから、このサイトで探して ioredis の使い方を見るって方法が捗った - Redis の DB を切り替える方法
I would recommend you create two separate clients each connect to a different database instead of using
select
to avoid potential conflictions.
cf. question on multiple databases · Issue #466 · luin/ioredis · GitHub
ioredis では select()
を使うより new Redis({db: 1})
のように別クライアントを作るほうが良いっぽい
- 作者:Josiah L. Carlson
- 発売日: 2013/12/27
- メディア: 大型本
さよぽに の「自転車えくすぷれす」いい曲なので聴いて!