Edited at

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

More than 1 year has passed since last update.


背景

仕様検討中は 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定義を読み取って、スクリプトで生成するのもそれほど難しくなさそうです。