まず始めに
おはようございます。こんにちは。こんばんは!
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
から別タブで開いてください。
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
から別タブで開いてください。
まだデータを作成していないので、レスポンス結果は空ですね。
* Cloud9を利用されている方は3000の部分は8080で
$ curl http://localhost:3000/books
[]
seedファイルでBookデータを3個作成
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なども多くの企業で導入されている傾向があります。
API to APIなやりとりが出来る
例えば、決済関連のデータの扱いを別のRails APIに担当してもらったり役割分割できます。
カスタマイズ性が上がって変化に強い設計ができるわけですね。
ここまでのまとめ
Railsで典型的なJSON形式でデータを返すAPIサーバーを作成してみました!
ざっくりとメリットデメリットにも図を用いて説明してみました!
Railsは爆速でAPIサーバーを作れる! 最高ですね。
APIサーバーとReactを繋げる
これまでAPIサーバーを作成する方法とメリットについて学びました。
しかし、APIサーバーだけだとどのように実際のプロダクトで利用されているかが分かりにくいと思います。
そこで RailsのViewの代わりになる別のアプリを作成してみましょう。
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の設定が必要になります。
参考
- Gemfileで以下を追記
gem 'rack-cors'
$ bundle install
- 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ポートで起動するのでアクセスすると。。。
おまけでボタンをクリックするとモーダルウィンドウで詳細を見れたり、閉じたりできるようにもしています。
Reactを使うとエレガントなViewにできますよ😄
まとめ
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サーバー構築体験🤔💭