【初心者向け】RailsAPIモードでCRUD処理を実装する方法

徒歩3分圏内にQBハウスがあることによって散歩ついでに散髪に行くことが可能になった23期スキンフェード昴です。

 

さて、今回はモダンなアプリ開発に欠かせない、rails apiモードに関して学習していきたいと思います。ちょっと長いです。

上から順に見ていくと、rails apiモードでデータのcrud処理ができるようになります。

いわゆるバックエンドにrails、フロントエンドにjavascriptのライブラリ(ReactやVueなど)の構成でアプリを作ることもできるんです。すごいです。rails apiモード。

では、早速開発を進めていきたいと思います。

 

開発環境

rails  6.1.4
ruby   2.6.7
node   12.22.6
mysql  5.7.36

apiモードでrails new

Rails APIモードとは、API作成に特化したモードのことです。

APIモードではMVCのV(ビュー)が存在しないため、rails newを実行した際にビューに関するファイルやGemが生成されません。

apiモードでrails newを実行すると、viewを生成しなくなる。APIモード = JSONを返すモードと解釈してもいいらしい。今回は、mysqlをDBとして扱う。

$ rails  new api-sample -d mysql --api

db作成

$ rails db:create
Running via Spring preloader in process 64897
Created database 'api_sample_development'
Created database 'api_sample_test'

CORS(Cross-Origin Resource Sharing)の設定

ざっくり説明すると、 デフォルトでは、React等の別のオリジンからRailsAPIにアクセス(GETPOSTPUTDELETEなど)することは制限されています

フロントとバックで切り分けることはsame origin policyに反した行為だそう。Webページを生成したドメイン以外へのHTTPリクエストへアクセス(クロスドメインアクセス)したい場合に有用なのがCORSとのこと。クロスドメインアクセスを実現する事ができる。

具体的に、config/initializer配下にcors.rbを作成することで、クロスドメインアクセスを実現できる。

Rails.application.config.middleware.insert_before 0, Rack::Cors do
    allow do
      origins '<http://localhost:3000>'
  
      resource '*',
          headers: :any,
          methods: [:get, :post, :put, :patch, :delete, :options, :head],
          credentials: true
    end
  end

Pumaの設定

バックエンドのport番号と被ることを防ぐために3010に変えておく。

portENV.fetch("PORT") { 3010 }

適当なモデルの作成

自分の好きなモデル名、カラム名を任意で作成する

rails g model Alcohol name:string alcohol_percentage:integer price:integer
rails g model Customer name:string favorite_alcohol:string
rails g model Owner name:string
rails g model Shop name:string

rails-erdで作成したDB設計図

Image from Gyazo

サーバーにアクセスしてみる

rails s

お馴染みのyay you’re on railsが表示される

Image from Gyazo

ルーティングの構成を確認

それぞれCRUDができる状態になっている

routes.rb

Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :customers, only: %i[index create update destroy]
      resources :shops, only: %i[index create update destroy]
      resources :alcohols, only: %i[index create update destroy show]
      resources :owners, only: %i[index create update destroy]
    end
  end
  # For details on the DSL available within this file, see <https://guides.rubyonrails.org/routing.html>
end

コンソールでも確認してみる。

$rails routes --expanded
--[ Route 1 ]--------------------------------------------------------------------------------------
Prefix            | api_v1_customers
Verb              | GET
URI               | /api/v1/customers(.:format)
Controller#Action | api/v1/customers#index
--[ Route 2 ]--------------------------------------------------------------------------------------
Prefix            | 
Verb              | POST
URI               | /api/v1/customers(.:format)
Controller#Action | api/v1/customers#create
--[ Route 3 ]--------------------------------------------------------------------------------------
Prefix            | api_v1_customer
Verb              | PATCH
URI               | /api/v1/customers/:id(.:format)
Controller#Action | api/v1/customers#update
--[ Route 4 ]--------------------------------------------------------------------------------------
Prefix            | 
Verb              | PUT
URI               | /api/v1/customers/:id(.:format)
Controller#Action | api/v1/customers#update
--[ Route 5 ]--------------------------------------------------------------------------------------
Prefix            | 
Verb              | DELETE
URI               | /api/v1/customers/:id(.:format)
Controller#Action | api/v1/customers#destroy
--[ Route 6 ]--------------------------------------------------------------------------------------
Prefix            | api_v1_shops
Verb              | GET
URI               | /api/v1/shops(.:format)
Controller#Action | api/v1/shops#index
--[ Route 7 ]--------------------------------------------------------------------------------------
Prefix            | 
Verb              | POST
URI               | /api/v1/shops(.:format)
Controller#Action | api/v1/shops#create
--[ Route 8 ]--------------------------------------------------------------------------------------
Prefix            | api_v1_shop
Verb              | PATCH
URI               | /api/v1/shops/:id(.:format)
Controller#Action | api/v1/shops#update
--[ Route 9 ]--------------------------------------------------------------------------------------
Prefix            | 
Verb              | PUT
URI               | /api/v1/shops/:id(.:format)
Controller#Action | api/v1/shops#update
--[ Route 10 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | DELETE
URI               | /api/v1/shops/:id(.:format)
Controller#Action | api/v1/shops#destroy
--[ Route 11 ]-------------------------------------------------------------------------------------
Prefix            | api_v1_alcohols
Verb              | GET
URI               | /api/v1/alcohols(.:format)
Controller#Action | api/v1/alcohols#index
--[ Route 12 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | POST
URI               | /api/v1/alcohols(.:format)
Controller#Action | api/v1/alcohols#create
--[ Route 13 ]-------------------------------------------------------------------------------------
Prefix            | api_v1_alcohol
Verb              | PATCH
URI               | /api/v1/alcohols/:id(.:format)
Controller#Action | api/v1/alcohols#update
--[ Route 14 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | PUT
URI               | /api/v1/alcohols/:id(.:format)
Controller#Action | api/v1/alcohols#update
--[ Route 15 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | DELETE
URI               | /api/v1/alcohols/:id(.:format)
Controller#Action | api/v1/alcohols#destroy
--[ Route 16 ]-------------------------------------------------------------------------------------
Prefix            | api_v1_owners
Verb              | GET
URI               | /api/v1/owners(.:format)
Controller#Action | api/v1/owners#index
--[ Route 17 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | POST
URI               | /api/v1/owners(.:format)
Controller#Action | api/v1/owners#create
--[ Route 18 ]-------------------------------------------------------------------------------------
Prefix            | api_v1_owner
Verb              | PATCH
URI               | /api/v1/owners/:id(.:format)
Controller#Action | api/v1/owners#update
--[ Route 19 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | PUT
URI               | /api/v1/owners/:id(.:format)
Controller#Action | api/v1/owners#update
--[ Route 20 ]-------------------------------------------------------------------------------------
Prefix            | 
Verb              | DELETE
URI               | /api/v1/owners/:id(.:format)
Controller#Action | api/v1/owners#destroy

アルコールを作成してみる

コントローラーの構成

api/v1/alcohols_controller.rb

class Api::V1::AlcoholsController < ApplicationController
  def index
    @alcohols = Alcohol.all
    render json: @alcohols
  end

  def show
    @alcohol = Alcohol.find(params[:id])
    render json: @alcohol
  end
    def create
    @shop = Shop.find(1)
      @alcohols = @shop.alcohols.new(alcohol_params)
      if @alcohols.save
      render json: @alcohols
      else
        render nil
      end
  end

  def update
    set_alcohol
    if @alcohol.update(alcohol_params)
      render json: @alcohol
    else
      render nil
    end
  end

  def destroy
    set_alcohol
    @alcohol.destroy!
    render json: @alcohol
  end
  private
  def set_alcohol
    @alcohol = Alcohol.find(params[:id])
  end

  def alcohol_params
    params.require(:alcohol).permit(:name, :price, :alcohol_percentage)
  end
end

Curlを使ってデータを作成(post)してみる

$ curl -X POST -H "Content-Type: application/json" -d '{"name": "ビール" : "alcohol_percentage": 5 : "price" : 500}' <http://localhost:3000/api/v1/alcohols>

Curlを使って作成したアルコールを取得(get)してみる

$ curl <http://localhost:3010/api/v1/alcohols>
[{"id":1,"name":"ビール","alcohol_percentage":5,"shop_id":1,"price":500,"created_at":"2022-01-05T12:49:27.927Z","updated_at":"2022-01-05T12:49:27.927Z"},{"id":2,"name":"ビール","alcohol_percentage":5,"shop_id":1,"price":1000,"created_at":"2022-01-05T12:52:35.709Z","updated_at":"2022-01-05T12:52:35.709Z"},{"id":3,"name":"ビール","alcohol_percentage":5,"shop_id":1,"price":500,"created_at":"2022-01-05T12:53:32.557Z","updated_at":"2022-01-05T12:53:32.557Z"}]SubarunoMacBook-puro-3:api-sample subaru$

ブラウザにURLを打ち込んで直接アクセスすることもできる

Image from Gyazo

Curlを使って作成したアルコール詳細(show)を取得(get)してみる

$ curl <http://localhost:3010/api/v1/alcohols/1>
{"id":1,"name":"ビール","alcohol_percentage":5,"shop_id":1,"price":500,"created_at":"2022-01-05T12:49:27.927Z","updated_at":"2022-01-05T12:49:27.927Z"}

$ curl <http://localhost:3010/api/v1/alcohols/2>
{"id":2,"name":"ビール","alcohol_percentage":5,"shop_id":1,"price":1000,"created_at":"2022-01-05T12:52:35.709Z","updated_at":"2022-01-05T12:52:35.709Z"}

Curlを使って作成したアルコールを削除(delete)してみる

$ curl -X DELETE <http://localhost:3010/api/v1/alcohols/1>
{"id":1,"name":"ビール","alcohol_percentage":5,"shop_id":1,"price":500,"created_at":"2022-01-05T12:49:27.927Z","updated_at":"2022-01-05T12:49:27.927Z"}

Curlを使って作成したアルコールの情報を更新(put)してみる

$ curl -X PUT <http://localhost:3010/api/v1/alcohols/2> -d 'alcohol[name]="濃いめのレモンサワー"&alcohol[price]=400&alcohol[alcohol_percentage]=5'
{"name":"\\"濃いめのレモンサワー\\"","price":400,"alcohol_percentage":5,"id":2,"shop_id":1,"created_at":"2022-01-05T12:52:35.709Z","updated_at":"2022-01-05T13:21:06.296Z"}

まとめ

  • バックエンドをrailsapiモードで実装することで、フロントエンドにjavascriptのライブラリ(ReactやVue)を使用する事が容易になる。
  • Apiのレスポンスやリクエストを試す際には、CurlやPostmanが便利

【Rails】Rails6でAPIモードの環境構築をしっかりやる

https://github.com/r7kamura/autodoc

https://github.com/ruby-grape/grape

RailsでAPIを作成するために色々比較したので所感と実装方法のご紹介 - Qiita

React + Rails API モードで基本的な CRUD アプリを作ってみた (フロントエンド編 その1)

RailsのAPIモードを試してみた話 - のんびりきままな開発日記