92
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DMM WEBCAMPAdvent Calendar 2021

Day 25

RailsでWeb APIを作成する方法とメリット🤔💭

Last updated at Posted at 2021-12-24

まず始めに

おはようございます。こんにちは。こんばんは!
DMM WEBCAMP Advent Calendarの最終日を担当させていただきます

メンターのtanidaです!

今回はRailsで典型的なWeb APIサーバーを構築するハンズオンになります! よろしくお願いします!

*あまり細かい用語の説明はしませんが随時更新していく予定です。

この記事で完成したRails APIのソースコードです。

途中で利用するReactのサンプルコードです。

この記事の対象者

  • Ruby on Railsでアプリを作ったことがある人。

  • Ruby on Railsの環境構築ができる人。

  • Rails の API モードでサーバーの構築がしたい人。

典型的なREST APIを作成!

Ruby, Railsのバージョン

  • Ruby 2.6.3

  • Rails 6.1系

webpacker使わないので別に5系でもいいですがソースコードはこのバージョンです。

APIサーバーを作成

お好きなディレクトリでrails newを実行してください。

APIモードでRailsをつくるので--apiオプションを使います。

$ rails new rails_api_sample --api

$ cd rails_api_sample

# 必須のオプションではありませんが -j4 つけると少しインストールが速くなります。
$ bundle install -j4

$ rails s

rails s後に以下のような画面が出ていればOK ↓

http://localhost:3000 の部分はご自身のものに合わせてください。

*Cloud9を利用されている方は Preview > Preview Application から別タブで開いてください。

スクリーンショット 2021-12-25 1.11.42.png

APIサーバーを作ったことがない人向けに簡単に説明するとRailsのViewがないバージョンです。

Viewに当たる部分は、別のアプリケーションで担います。

近年だとReactやVueやAngulerとかが流行ってます。(個人的にはReactが好きです。)

scaffoldでサクッとRouting, Controller, Model, Migrationを用意

scaffoldでサクッとRouting、Controller、Model、Migrationファイルをサクッと作成します。
controller内には自動でindex, show, create, update, destoryに相当するアクションも追記されます。

(繰り返しますがAPIモードなのでViewはありませんよ。)
(APIモードだとnewアクションは不要だと判断されてcontroller内にもありません。)

RailsのサクッとCRUD機能を作れちゃう辺り本当に便利だなぁとつくづく思います。

$ rails g scaffold book title:string body:text

以下を実行してstringのtitle、textのbodyというカラムを持ったbooksテーブルを作成します。

$ rails db:migrate

/booksのパスにアクセスしてすべてのBookの情報を取得してみます。

$ rails s

ブラウザか、curlコマンドで /books のパスでアクセスしてみてください。

http://localhost:3000 の部分はご自身のものに合わせてください。

*Cloud9を利用されている方は Preview > Preview Application から別タブで開いてください。

スクリーンショット 2021-12-26 1.55.10.png

まだデータを作成していないので、レスポンス結果は空ですね。

* Cloud9を利用されている方は3000の部分は8080で

$ curl http://localhost:3000/books

[]

seedファイルでBookデータを3個作成

seeds.rbに以下を追記

db/seeds.rb
3.times do |i|
  Book.create(title: "タイトル #{i}", body: "内容 #{i}")
end

DBにデータを作成!

$ rails db:seed

もう一度curlでRailsに問い合わせするとデータがちゃんと3個返ってきました。

(BooksControllerのindexアクションにアクセスしています。)

$ curl http://localhost:3000/books

[{"id":1,"title":"タイトル 0","body":"内容 0","created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:33:35.507Z"},
{"id":2,"title":"タイトル 1","body":"内容 1","created_at":"2021-12-24T16:33:35.512Z","updated_at":"2021-12-24T16:33:35.512Z"},
{"id":3,"title":"タイトル 2","body":"内容 2","created_at":"2021-12-24T16:33:35.516Z","updated_at":"2021-12-24T16:33:35.516Z"}]

curlコマンドでAPIに問い合わせてCRUD体験

curlコマンドでRailsにアクセスしてみます。

初めてcurlコマンドを見る方は、見るのも嫌になるかもしれないですが簡単にいうとターミナルからHTTPリクエストしているだけです。

curlコマンドの書き方を覚えてほしいのではなくRailsにアクセスすると、
以下のようなことができるんだなぁと理解できればそれでひとまずはOKです!

  • データをすべて取得
  • データの一部を取得
  • 1つのデータを更新
  • 1つのデータを削除

ここで理解していただきたいのは

APIサーバー(Rails)にアクセスすると上記のCRUDな機能が利用できるんだなぁ〜ということだけです。😌

*留意点

Cloud9を利用されている方は http://localhost8080 でアクセスしてください。

データを取得してみましょう

すべてのBookを取得してみます。
(BooksControllerのidexアクションにアクセスしています。)

$ curl http://localhost:3000/books

[{"id":1,"title":"変更したのだ","body":"変更したのだ","created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:52:33.141Z"},
{"id":2,"title":"タイトル 1","body":"内容 1","created_at":"2021-12-24T16:33:35.512Z","updated_at":"2021-12-24T16:33:35.512Z"},
{"id":3,"title":"タイトル 2","body":"内容 2","created_at":"2021-12-24T16:33:35.516Z","updated_at":"2021-12-24T16:33:35.516Z"}]

Bookを一つ取得してみます。
(BooksControllerのshowアクションにアクセスしています。)

$ curl http://localhost:3000/books/1

{"id":1,"title":"変更したのだ","body":"変更したのだ","created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:52:33.141Z"}

データを作成してみましょう

新しいBookを作成してみます。
(BooksControllerのcreateアクションにアクセスしています。)

curlコマンドの雑な説明をすると以下を指定しています。

  • -H はHTTPのヘッダの指定
  • -XはHTTP verbの指定
  • -d(-data)はデータの指定
$ curl -H "Content-Type: application/json" -X POST -d '{"title": "hoge", "body": "hoge"}' http://localhost:3000/books

{"id":5,"title":"hoge","body":"hoge","created_at":"2021-12-24T16:41:24.118Z","updated_at":"2021-12-24T16:41:24.118Z"}

確認すると一個データが増えてますね。

$ curl http://localhost:3000/books

[{"id":1,"title":"タイトル 0","body":"内容 0","created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:33:35.507Z"},
{"id":2,"title":"タイトル 1","body":"内 容 1","created_at":"2021-12-24T16:33:35.512Z","updated_at":"2021-12-24T16:33:35.512Z"},
{"id":3,"title":"タイトル 2","body":"内容 2","created_at":"2021-12-24T16:33:35.516Z","updated_at":"2021-12-24T16:33:35.516Z"},
{"id":4,"title":"hoge","body":"hoge","created_at":"2021-12-24T16:40:36.498Z","updated_at":"2021-12-24T16:40:36.498Z"},

データを削除してみましょう

id 4 の book を削除してみます。
(BooksControllerのdestroyアクションにアクセスしています。)

curl -X DELETE http://localhost:3000/books/4

データが一つ消えてますね。

$ curl http://localhost:3000/books

[{"id":1,"title":"タイトル 0","body":"内容 0","created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:33:35.507Z"},
{"id":2,"title":"タイトル 1","body":"内 容 1","created_at":"2021-12-24T16:33:35.512Z","updated_at":"2021-12-24T16:33:35.512Z"},
{"id":3,"title":"タイトル 2","body":"内容 2","created_at":"2021-12-24T16:33:35.516Z","updated_at":"2021-12-24T16:33:35.516Z"}]

データの更新をしてみましょう

id 1 の Bookの更新をしてみます。
(BooksControllerのupdateアクションにアクセスしています。)

$ curl -H "Content-Type: application/json" -X PATCH -d '{"title": "変更したのだ", "body": "変更したのだ"}' http://localhost:3000/books/1

{"title":"変更したのだ","body":"変更したのだ","id":1,"created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:52:33.141Z"}

データが確かに変更されていますね。

$ curl http://localhost:3000/books

[{"id":1,"title":"変更したのだ","body":"変更したのだ","created_at":"2021-12-24T16:33:35.507Z","updated_at":"2021-12-24T16:52:33.141Z"},
{"id":2,"title":"タイトル 1","body":"内容 1","created_at":"2021-12-24T16:33:35.512Z","updated_at":"2021-12-24T16:33:35.512Z"},
{"id":3,"title":"タイトル 2","body":"内容 2","created_at":"2021-12-24T16:33:35.516Z","updated_at":"2021-12-24T16:33:35.516Z"}]

APIサーバー...RailsからViewを無くしてるのに何が嬉しいん?🤔

別のアプリと、Railsを組み合わせられます

マイクロサービス化と呼ばれるやつです。

機能ごとに小さなアプリを作り、組み合わせることで大きな機能を構築していく設計手法です。

実際どんな感じか図で見ていきましょう。

Viewに別のアプリを使う

RailsのViewだと正直UI, UXのレベルに限界があります。

見た目をゴリゴリに動かしたりエレガントにしたい場合はJavaScriptのライブラリであるJQueryを使うのもありですが、RailsのView自体を使わないことも多かったりします。

流行りでいうとJavaScriptのライブラリ、フレームワークにあたるReact, Vue, Angularがあります。

ReactのフレームワークのNext.js, Gatsyby.jsやVueのフレームワークのNuxt.jsなども多くの企業で導入されている傾向があります。

スクリーンショット 2021-12-25 2.23.26.png

API to APIなやりとりが出来る

例えば、決済関連のデータの扱いを別のRails APIに担当してもらったり役割分割できます。

カスタマイズ性が上がって変化に強い設計ができるわけですね。

スクリーンショット 2021-12-25 2.37.17.png

ここまでのまとめ

Railsで典型的なJSON形式でデータを返すAPIサーバーを作成してみました!

ざっくりとメリットデメリットにも図を用いて説明してみました!

Railsは爆速でAPIサーバーを作れる! 最高ですね。

APIサーバーとReactを繋げる

これまでAPIサーバーを作成する方法とメリットについて学びました。

しかし、APIサーバーだけだとどのように実際のプロダクトで利用されているかが分かりにくいと思います。

そこで RailsのViewの代わりになる別のアプリを作成してみましょう。

スクリーンショット 2021-12-25 2.23.26.png

Viewを担う別のアプリとしてJavaScriptのライブラリである React を用います。

前提

  • Reactがどういうものなのかは説明していません。

ぜひ公式サイトをご参照ください。

  • ES2015以降のJavaScriptを知っていないとコードを理解するのは難しいです。

2015年以降のJavaScriptを学びたい方はぜひJS Primerを見ることをお勧めします。

  • ご使用のマシンにNode.jsがインストールされている必要があります。

ターミナルで、node -v を実行してバージョンが出たらインストールできています。
インストールされていない方は公式からLTS(long term support)版をインストールしていれば良いでしょう。

  • Cloud9の人はすみませんこれからやる方法ではできません。😞

CORSの設定をしてRails APIサーバーを起動

CORSとは何かを簡単にいうと、どこからのリクエストを許可するかを決めています。

Rails は http://localhost:3001 で起動して

React は http://localhost:3000 で起動していきます。

プロトコル、ドメイン、ポートのどれかが一致していないもの同士で通信のやり取りをする場合は、CORSの設定が必要になります。

今回はポートが異なるのでやはりCORSの設定が必要になります。

参考

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

  • Gemfileで以下を追記
gem 'rack-cors'
$ bundle install
  • config/initializers/cors.rbを開いて以下を追記
config/initializers/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]
  end
end

3001ポートで起動します。

$ rails s -p 3001

Reactアプリを起動する

まずNode.jsがインストールされているか確認します。

$ node -v
v16.13.1

作成済みのReactアプリケーションがあるのでcloneして立ち上げます。
サンプルコード

$ git clone git@github.com:digitter/react-sample.git

$ cd react-sample

$ npm install

$ npm run start

APIサーバーからBookの情報を取ってきて表示するようにしてあります。

Reactが3000ポートで起動するのでアクセスすると。。。

スクリーンショット 2021-12-26 22.06.44.png

おまけでボタンをクリックするとモーダルウィンドウで詳細を見れたり、閉じたりできるようにもしています。

Reactを使うとエレガントなViewにできますよ😄

スクリーンショット 2021-12-28 22.42.49.png

まとめ

APIサーバーとReactを繋げてみました。

このようにAPIとフロントエンドの別アプリでやり取りするという設計は多くのアプリケーションで利用されています。

# GraphQL関連を期待してた人へ(🙏😞🙏)

この記事は今回のWeb APIと比較してGraphQLサーバーを使ってみたかったのですが、
当方の時間の確保が難しく RailsのWeb APIサーバの作成Reactとやり取りする ところまでに止めました。

予めカレンダーのタイトルを見ていてGraphQL関連の内容を期待していた人はごめんなさい。🙏😞🙏

Railsで作るGraphQLサーバーの話は年末までに別記事でまとめてみようと思います。
(この記事をストックしていただけたら新しい記事を出した時に通知がいくようにします。)

皆さんがAPIと仲良くなってくれると幸いです。₍₍(ง˘ω˘)ว⁾⁾API

この記事の続きとしてRails APIでGraphQLサーバーの構築もしていますので興味がある方はぜひご参照ください。

  • 12/26

    • Reactと繋げるところまで完了
  • 12/28

    • Reactアプリの見た目をちょっとだけいい感じに変更(モーダルウィンドウで表示)
    • Date time をYYYY年MM月DD日で出力するように変更(Moment.jsの後継ライブラリLuxonを使用)
  • 12/30

    • RailsでGraphQLサーバー構築体験🤔💭

92
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
92
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?