Ruby on RailsのAPIサーバーのスタブを手動で作成する

背景

仕様検討中は Swaggerを使ってAPI仕様を共有する - Qiita に見るように、SwaggerなどAPI仕様からソースコードを生成するコードジェネレーターを使って、柔軟にAPIのインタフェースを変更するのが便利です。

仕様が固まって開発に入る際に、Swaggerの生成したRailsのソースコードを流用しようとすると、次のような問題が出てきます。

  • Railsのバージョンが5.0固定
  • 含まれるモジュール構成(sprocketsなど)が固定
  • DBがMySQL固定

実際に作りたいRailsアプリケーションは様々な構成になると思います。
そこで、API仕様に合わせたスタブサーバーを手動で作る方法をここにまとめます。

アプリケーションの要件

  • Rails 5.1.5
  • DBにPostgreSQLを使う
  • 画面のない純粋なAPIサーバー

作成

注意

  1. モデルやDBを扱わない、APIのみのスタブサーバーを目指します
  2. fish-shellを前提としています。bash等の場合は(pwd)$(pwd)に置き換えてください

開発環境のファイルを揃える

Gemfile

source 'https://rubygems.org'

gem 'rails', '~> 5.1.5'

ここで好みのRailsのバージョンを指定します。

Dockerfile

FROM ruby:2.5-alpine3.7

ENV BUILD_PACKAGES="curl-dev ruby-dev build-base bash" \
    DEV_PACKAGES="zlib-dev libxml2-dev libxslt-dev tzdata yaml-dev postgresql-dev" \
    RUBY_PACKAGES="ruby-json yaml"

# Update and install base packages and nokogiri gem that requires a
# native compilation
RUN apk update && \
    apk upgrade && \
    apk add --no-cache --update\
    $BUILD_PACKAGES \
    $DEV_PACKAGES \
    $RUBY_PACKAGES && \
    mkdir -p /myapp

# Copy the app into the working directory. This assumes your Gemfile
# is in the root directory and includes your version of Rails that you
# want to run.
WORKDIR /myapp
COPY Gemfile /myapp
#COPY Gemfile.lock /myapp

RUN gem install bundler
RUN bundle config build.nokogiri --use-system-libraries && \
    bundle install --jobs=4 --retry=10 --clean

使いたいデータベースに合わせて、postgresql-devsqlite-dev(SQLite3)やmariadb-dev(MySQL)に変更します。

Dockerイメージをビルド

Dockerイメージをビルド

docker build -t temp .

Rails new

Railsアプリケーションの雛形を作成

docker run --rm -it -v (pwd):/myapp temp rails new . -MCBSJT --skip-yarn --database=postgresql --api
オプション 意味
--database=postgresql Preconfigure for selected database
--skip-yarn Don't use Yarn for managing JavaScript dependencies
M Skip Action Mailer files
C Skip Action Cable files
B Don't run bundle install
S Skip Sprockets files
J Skip JavaScript files
T Skip test files
-api Preconfigure smaller stack for API only apps

使いたい機能にあわせてオプションを調整します。

オプションを知りたい時

rails new --helpで確認できます。
今回の環境では次のコマンドを使います。

docker run --rm -it -v (pwd):/myapp temp rails new --help

やり直したい時

オプション指定を変更して作り直したい時があります。

Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.
Type 'rails' for help.

とエラーが出ます。
binディレクトリの有無を見ています。削除すれば、再実行できます。

GemをDockerイメージにインストール

必要なGemをDockerイメージにインストールするために、Dockerイメージをビルドしなおします。

docker build -t temp .

起動確認

docker run --rm -it -v (pwd):/myapp -p 80:3000 temp rails s -b 0.0.0.0

http://localhost でRailsの初期画面が開きます。

スクリーンショット 2018-03-16 15.04.53.png

コントローラーを実装

ユーザー一覧APIを作って見ましょう

コントローラーを生成

scaffold_controllerを使うと、モデルを作ってしまうので、controllerを指定します。

docker run --rm -it -v (pwd):/myapp temp bin/rails generate controller api/v1/users index

usersが複数形であることに気をつけてください。

ルーティングの変更

config/routes.rbを更新します。

namespace :api do
  namespace :v1 do
    get 'users/index'
  end
end

と不思議なルーティングが生成されます。

routes.rb
namespace :api do
  namespace :v1 do
    get 'users', to: 'users#index'
  end
end

に修正します。

メソッド名(get, post)やメソッド名(create, update)は適宜変更します。

コントローラーの実装

生成したapp/controllers/api/v1/users_controller.rbに仮データを返す実装をします。

def index
  render json: [{
    name: '太郎',
    age: 21
  }, {
    name: '花子',
    age: 29
  } ]
end

動作確認

curlコマンドを使って動作確認します。

curl 'http://localhost/api/v1/users'

続けてコントローラーを作る

あとは、事前に決めたAPI仕様にしたがって機械的にAPIを実装していきます。

続いて複数のコントローラーを作るときは

docker run --rm -it -v (pwd):/myapp -p 80:3000 temp bash

でdockerコンテナ上でbashを起動し

bin/rails generate controller Users show

railsコマンドを直接実行すると、毎回Dockerコンテナを起動し直さなくて良いので、効率が良いです。

まとめ

Swagger CodegenでAPIサーバーのスタブを生成できます。
しかし、実際の開発環境とはギャップがあります。
ギャップを柔軟に埋めるには腕力を使いましょう。

課題

生成しているのは、APIごとに

  1. *_controller.rb
  2. routes.rb

の2ファイルです。Railsのジェネレーターを使わずに、swagger.ymlをパースしAPI定義を読み取って、スクリプトで生成するのもそれほど難しくなさそうです。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.