RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

JSON Serverで30秒で認証機能付きモックREST APIを構築する

f:id:tech-rakus:20201028215031p:plain こんにちは。株式会社ラクスで先行技術検証を行っている技術推進課のt_okkanです。

現在、フロントエンドの技術検証をしているのですが、手頃にバックエンドのAPIを構築したいと思いJSON Serverを利用しました。 同じようにバックエンドを手軽に構築する手段としては、FirebaseなどのBaaSを利用することがあげられますが、より手軽にローカルで構築できる手法を紹介しようと思います。 さらに今回はDockerでのJSON Serverの構築と、デフォルトのJSON Serverの機能を拡張し認証機能を追加する方法を紹介しようと思います。

JSON Server

JSON Serverは、フロントエンド開発者向けプロトタイピング時のバックエンドAPIのモック作成ライブラリです。ローカルに用意したJSONファイルをリソースとしてAPIを構築することができ、そのJSONファイルの構成から自動的にURLが生成されます。

www.npmjs.com

Expressベースでサーバーを構築しているので、Expressのモジュールを使用してカスタマイズを実装できます。 今回はその仕組みを利用して、認証機能付きのJSON Serverを構築します。

タイトルの30秒で構築できるはコードがあれば、30秒で構築できるということです。 デフォルトの認証なしの機能なら、Getting started通りに構築するとコードレスで、30秒でREST APIを構築できます。

公式ドキュメントでもアピールしています。

Get a full fake REST API with zero coding in less than 30 seconds (seriously)

JSON Serverの実装

フォルダー構成

今回構築するAPIサーバーのフォルダー構成は以下のようになります。./serverフォルダー内にDockerコンテナへ配置する、JSON Server用のファイル群を配置します。

./ 
|- server
|    |- data
|    |   |- data.json
|    |- server.js
|    |- package.json
|- docker-compose.yml
|- Dockerfile

server.jsにはExpressのモジュールを利用してデフォルトのJson Serverをカスタマイズした機能を実装します。今回は認証処理を実装します。

data.jsonにはAPIで管理するリソースデータを記述します。

API仕様

今回構築するAPIサーバーの主な仕様です。このほかにもPUTDELETEも使用できます。 今回はブログ記事のAPIを想定しています。ログイン・ブログ記事取得、のAPIにのみ認証なしアクセスでき、それ以外のAPIにアクセスするには認証が必要となります。

URL メソッド 機能 認証
http://localhost:33000/blogs GET ブログ一覧取得 なし
http://localhost:33000/blogs POST ブログ記事追加 あり
http://localhost:33000/blogs/:id GET ブログ取得 なし
http://localhost:33000/users GET ユーザー一覧取得 あり
http://localhost:33000/users/:id GET ユーザー一覧取得 あり
http://localhost:33000/auth/login POST ログイン なし

data.json

data.jsonはデータベースのように、APIで扱うデータを保存します。今回は、ユーザー情報とブログ情報を保存するようにします。

{
  "blogs": [
    {
      "id": 1,
      "title": "Java",
      "body": "Java Beans",
      "post": "2020/10/01",
      "userid": 1
    },
    {
      "id": 2,
      "title": "Python",
      "body": "Python3.10",
      "post": "2020/10/04",
      "userid": 1
    },
    {
      "id": 3,
      "title": "JavaScript",
      "body": "Vue.js",
      "post": "2020/10/10",
      "userid": 2
    }
  ],
  "users": [
    {
      "id": 1,
      "name": "user one",
      "email": "one@example.com",
      "password": "userone"
    },
    {
      "id": 2,
      "name": "user two",
      "email": "two@example.com",
      "password": "usertwo"
    }
  ]
}

JSON Serverの実装

ではプログラムを実装し、JSON Serverを拡張し認証付きREST APIサーバーを構築していきます。

まずはNode.jsのプロジェクトのpackage.jsonを以下のように設定します。

{
    "name": "json-server-docker",
    "version": "1.0.0",
    "description": "Json Server on Docker",
    "author": "XXXX@example.com",
    "main": "server.js",
    "scripts": {
        "start": "node server.js"
    },
    "dependencies": {
        "body-parser": "^1.19.0",
        "helmet": "^4.1.1",
        "json-server": "^0.16.1",
        "jsonwebtoken": "^8.5.1"
    }
}

main, scripts, dependencies以外は好みの値に設定してください。 今回は認証にJWTでのトークン認証を使用するので、jsonwebtokenを依存関係に追加します。

では次に、サーバー本体となるserver.jsを以下のように実装します

const jsonServer = require("json-server");
const fs = require("fs");
const bodyParser = require("body-parser");
const jwt = require("jsonwebtoken");
const helmet = require("helmet");

// JSON Serverで使用するJSONファイルを設定
const server = jsonServer.create();
const router = jsonServer.router("./data/data.json");
// JSON形式のリクエスト対応
server.use(bodyParser.urlencoded({ extended: true }));
server.use(bodyParser.json());

// 署名
const JWT_SECRET = "jwt_json_server";
// 有効時間
const EXPIRATION = "1h";

// データーベースの作成
const db = JSON.parse(fs.readFileSync("./data/data.json", "UTF-8"));

// ①ログイン用のルート
server.post("/auth/login", (req, resp) => {
  const { email, password } = req.body;
  // ログイン検証
  if (
    db.users.findIndex(
      (user) => user.email === email && user.password === password
    ) === -1
  ) {
    resp.status(401).json("Unauthorized");
    return;
  }

  // ログイン後、アクセストークンの生成
  const access_token = jwt.sign({ email, password }, JWT_SECRET, {
    expiresIn: EXPIRATION,
  });

  resp.status(200).json({ access_token });
});

// ②ログイン認証が必要ないルート
// 記事一覧を取得
server.get("/blogs", (req, resp) => {
  const blogs = db.blogs;
  resp.status(200).json({ blogs });
});
// 記事IDから記事を取得
server.get("/blog/:id", (req, resp) => {
  const id = req.params.id;
  const blog = db.blogs.find((blog) => blog.id === Number(id));
  resp.status(200).json({ blog });
});

//③ 認証が必要なルート
server.use((req, resp, next) => {
  // 認証形式チェック
  if (
    req.headers.authorization === undefined ||
    req.headers.authorization.split(" ")[0] !== "Bearer"
  ) {
    // 認証形式が異なる場合
    resp.status(401).json("Unauthorized");
    return;
  }

  // 認証チェック
  try {
    var decode = jwt.verify(
      req.headers.authorization.split(" ")[1],
      JWT_SECRET
    );
    // 認証に成功した場合は、next関数を実行しJSON Serverの機能を利用する
    next();
  } catch (e) {
    // 認証に失敗した場合
    resp.status(401).json("Unauthorized");
  }
});

// JSON Serverを起動する
server.use(router);
server.use(helmet);
server.listen(33000, () => {
  console.log("JSON Server Start");
});

JsonServer Access Controlを参考に実装しました。 実装したルーターとしては、

  1. ログイン用(/auth/login
  2. 認証なしで公開(/blogs/blogs/:id
  3. 上記以外で認証が必要

の3種類を実装しています。

jsonwebtokenや、body-parserの使い方はこちらを参考にしています。

jsonwebtoken - npm

body-parser - npm

Docker環境

Dockerを用いてJSON Serverを構築します。Dockerfiledocker-compose.ymlは以下のようにしました。

  • Dockerfile
FROM node:latest

RUN yarn add global json-server
  • docker-compose.yml
version: "3"
services:
  json-server:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./server:/data/server:delegated
    tty: true
    working_dir: /data/server
    command: sh -c "yarn install && yarn start"
    container_name: jsonserver-docker
    ports:
      - "33000:33000"

実行

では最後にDockerコンテナ上で実行しましょう。

$ docker-compose build
$ docker-compose up -d

起動後にcurlhttp://localhost:33000/usersにアクセスしてください。認証をしていないので、Unauthorizedが返ってきます。

$ curl http://localhost:33000/users
"Unauthorized"

/auth/loginでログインしてから、レスポンスのアクセストークンをヘッダーに付与して同じURLにアクセスしてみます。

$ curl -X POST -H "Content-Type: application/json" -d '{"email": "one@example.com", "passowrd": "userone"}' http://localhost:33000/auth/login
{
  "access_token": "アクセストークン"
}
$ curl -H "Content-Type:application/json" -H "Authorization:Bearer アクセストークン" http://localhost:33000/users
[
  {
    "id": 1,
    "name": "user one",
    "email": "one@example.com",
    "password": "userone"
  },
  {
    "id": 2,
    "name": "user two",
    "email": "two@example.com",
    "password": "usertwo"
  }
]

レスポンスから分かるように、ユーザー一覧を取得できます。/blogsのGETメソッドとPOSTメソッドでも試してみてください。

まとめ

JSON Serverを利用して認証機能付きのモックREST APIを構築しました。 一度作成してしまえば、Dockerを起動するだけでいつでも30秒でバックエンドのAPIを構築できます。 日々の勉強や、ちょっとした検証などに利用してみてください。 GitHubにもコードを上げています。参考にしてみてください。

https://github.com/txkxyx/jsonserver-docker

github.com

Copyright © RAKUS Co., Ltd. All rights reserved.