🙆‍♀️

Rails API (Docker) の作成

2022/11/10に公開約5,500字

個人サービスの作成 && 勉強の為に Rails の API サービスの作成を行います。

作成したサンプルはこちら
https://github.com/chikugoy/rails_api_and_rspec_for_docker

インストール用のDocker

以下のようなディレクトリ、ファイル構成でDocker用のファイルを作成します。

  • docker
    • Dockerfile
    • entrypoint.sh
  • docker-compose.yml
Dockerfile
FROM ruby:3.1

ENV TZ=Asia/Tokyo
ARG RUBYGEMS_VERSION=3.3.20

RUN apt update -qq && apt install -y postgresql-client

RUN mkdir /myapp
WORKDIR /myapp

COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN gem update --system ${RUBYGEMS_VERSION} && \
    bundle install
COPY . /myapp

COPY docker/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]
entrypoint.sh
#!/bin/bash
set -e

rm -f /myapp/tmp/pids/server.pid

exec "$@"
docker-compose.yml
version: "3.9"
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: password
  web:
    build:
      context: .
      dockerfile: ./docker/Dockerfile
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

railsのインストールと起動

プロジェクト直下にGemfileとGemfile.lockを用意します。
(Gemfile.lockは空)

Gemfile
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.1.2"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.0.4"

rails のインストールと起動を行います。

docker-compose build
docker-compose run web rails new . --force --no-deps --database=postgresql

--api オプションをつけると後のrails db:createでエラーになる為、つけない形で一旦回避しています

db の設定を行います

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

db の作成とrailsの起動を行います

docker-compose run web rails db:create
docker-compose up -d

起動確認
http://127.0.0.1:3000/

rails api の設定

config.api_only = trueの追加と、継承元をActionController::APIへ変更します。

app/controllers/application_controller.rb
class ApplicationController < ActionController::API
    config.api_only = true
end

rails api の確認

api確認用のテーブル、モデル、コントローラー作成

rails g model regex title:string
rails g controller regexes
rake db:migrate

API用のパスの設定

config/routes.rb
Rails.application.routes.draw do
  namespace 'api' do
    namespace 'v1' do
      resources :regexes
    end
  end
end

テストデータの投入

rails c
Regex.create(title:'title1')
Regex.create(title:'title2')

コントローラーの変更(指定した名前空間へ移動)

app/controllers/api/v1/regexes_controller.rb
module Api
  module V1
    class RegexesController < ApplicationController
      before_action :set_regex, only: [:show, :update, :destroy]

      def index
        regexes = Regex.order(created_at: :desc)
        render json: { status: 'SUCCESS', message: 'Loaded regexes', data: regexes }
      end

      def show
        render json: { status: 'SUCCESS', message: 'Loaded the regex', data: @regex }
      end

      def create
        regex = Regex.new(regex_params)
        if regex.save
          render json: { status: 'SUCCESS', data: regex }
        else
          render json: { status: 'ERROR', data: regex.errors }
        end
      end

      def destroy
        @regex.destroy
        render json: { status: 'SUCCESS', message: 'Deleted the regex', data: @regex }
      end

      def update
        if @regex.update(regex_params)
          render json: { status: 'SUCCESS', message: 'Updated the regex', data: @regex }
        else
          render json: { status: 'SUCCESS', message: 'Not updated', data: @regex.errors }
        end
      end

      private

      def set_regex
        @regex = Regex.find(params[:id])
      end

      def regex_params
        params.require(:regex).permit(:title)
      end
    end
  end
end

Postmanで以下のURLにGET
http://localhost:3000/api/v1/regexes

{
    "status": "SUCCESS",
    "message": "Loaded regexes",
    "data": [
        {
            "id": 2,
            "title": "title2",
            "created_at": "2022-11-10T07:55:56.123Z",
            "updated_at": "2022-11-10T07:55:56.123Z"
        },
        {
            "id": 1,
            "title": "title1",
            "created_at": "2022-11-10T07:55:49.070Z",
            "updated_at": "2022-11-10T07:55:49.070Z"
        }
    ]
}

rails api のテスト(rspec)

factory_bot_rails と rspec を追加

Gemfile
group :development, :test do
  gem 'factory_bot_rails'
  gem 'rspec-rails'
end

rspec の初期設定

bin/rails generate rspec:install

rspec のファイル生成コマンド

bin/rails g rspec:controller regexes

テストファイルを書き換える

spec/requests/api/v1/regexes_spec.rb
require 'rails_helper'

# logger
Rails.logger = Logger.new(STDOUT)

# SQL
# ActiveRecord::Base.logger = Logger.new($stdout) # SQLを出力
# ActiveRecord::Base.verbose_query_logs = true # SQLがコード上のどこで実行されたかを出力する

RSpec.describe "Regexes", type: :request do
  it '全てのポストを取得する' do
    FactoryBot.create_list(:regex, 10)

    get '/api/v1/regexes'
    json = JSON.parse(response.body)

    # リクエスト成功を表す200が返ってきたか確認する。
    expect(response.status).to eq(200)

    # 正しい数のデータが返されたか確認する。
    expect(json['data'].length).to eq(10)
  end
end

rspec 実行

bundle exec rspec

Discussion

ログインするとコメントできます