RailsのAPIモードでアプリケーション開発してみる 〜バックエンドのユーザ管理機能編〜
エンジニア目指して独学中なのですが、いろんな技術をリサーチしていく中で、こんな構成でアプリを作ってみたくなりました。
DB | MySQL |
バックエンド | RailsのAPIモード |
フロントエンド | React |
デザイン | Semantic UI React |
そんなわけで、今日はRailsのAPIモードでアプリケーションを作り、ユーザと投稿だけの最小限のCRUDアプリを実装していこうと思います。
Rails newの--api
オプション
Railsのバージョン6.0.0で、DBはMySQLを指定しつつ、---api
オプションでAPIモードのRailsプロジェクトを立ち上げます。
rails _6.0.0_ new try_api_react -d mysql --api
DeviseとDevise Token Auth導入
ユーザ管理に必要なGemを入れていきます。私の場合、Deviseのみでユーザテーブルを先に作ってしまっていたので、こちらの記事が参考になりました。
Gemfile
# Deviseを使ったUserテーブルがすでにある前提 gem 'devise_token_auth'
bundle install rails g devise_token_auth:install User auth
ユーザテーブルがすでに存在するので、Devise Token Authによって作成されたマイグレーションファイルを一旦削除し、カラム追加用のマイグレーションを作成します。(公式ガイド参照)
rails g migration AddTokensToUsers provider:string uid:string tokens:text
マイグレーションファイルの中身は公式ドキュメントのものをそのまま。
class AddTokensToUsers < ActiveRecord::Migration[6.0] # create migration by running a command like this (where `User` is your USER_CLASS table): # `rails g migration AddTokensToUsers provider:string uid:string tokens:text` def up add_column :users, :provider, :string, null: false, default: 'email' add_column :users, :uid, :string, null: false, default: '' add_column :users, :tokens, :text # if your existing User model does not have an existing **encrypted_password** column uncomment below line. # add_column :users, :encrypted_password, :null => false, :default => "" # the following will update your models so that when you run your migration # updates the user table immediately with the above defaults User.reset_column_information # finds all existing users and updates them. # if you change the default values above you'll also have to change them here below: User.find_each do |user| user.uid = user.email user.provider = 'email' user.save! end # to speed up lookups to these columns: add_index :users, [:uid, :provider], unique: true end def down # if you added **encrypted_password** above, add here to successfully rollback remove_columns :users, :provider, :uid, :tokens end end
rails db:migrate
Devise Token Authの各種設定
ルーティング
/api/v1/
のパスでDevise Token Authが使えるように設定します。
Rails.application.routes.draw do devise_for :users # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html namespace :api do scope :v1 do mount_devise_token_auth_for 'User', at: 'auth' end end end
リクエスト毎にアクセストークンが変わらないようにする
change_headers_on_each_request
の行のコメントアウトを外し、値をfalseにします。
# frozen_string_literal: true DeviseTokenAuth.setup do |config| # 省略 config.change_headers_on_each_request = false # 省略 # config.enable_standard_devise_support = false end 最後の行はもともと入れていたDeviseに何か関係がありそうですが、今回はデフォルトでコメントアウトされていました。
CORSを許可する
こちらの記事や公式ドキュメントを参考に、CORSを許可していきます。
Gemfile
gem 'rack-cors', :require => 'rack/cors'
bundle install
config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'localhost:3000' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
Reactの開発をポート8000番で行う場合は、許可するオリジンはlocalhost:8000
とすればいいのでしょうか。
POSTリクエストでユーザ登録してみる
それでは、CORS許可したポート3000番でサーバを立ち上げ、Advanced REST clientなどを使ってPOSTリクエストを投げて見ます。
rails s -p 3000
リクエスト内容
HTTPメソッド | POST |
URL | http://localhost:3000/api/v1/auth |
Header | Content-Type: application/json |
Body | {"email":"example222@example.com","password":"password","password_confirmation":"password"} |
すると、ユーザ登録が成功し、以下のようなレスポンスが返ってきました。
Response Header
x-frame-options: SAMEORIGIN x-xss-protection: 1; mode=block x-content-type-options: nosniff x-download-options: noopen x-permitted-cross-domain-policies: none referrer-policy: strict-origin-when-cross-origin access-token: WyW3o9LlV0ymwkPuKx84VQ token-type: Bearer client: P6LapCU5aaSKqLPO7JYAKA expiry: 1607828063 uid: example222@example.com content-type: application/json; charset=utf-8 etag: W/"f800f46c772f1529d26e671e3b8f2af4" cache-control: max-age=0, private, must-revalidate x-request-id: e0803dc4-db45-44ea-a160-8d2f1af7d46f x-runtime: 0.278159 vary: Origin transfer-encoding: chunked
Response Body
{ "status": "success", "data": { "id": 3, "email": "example222@example.com", "created_at": "2020-11-29T02:54:23.394Z", "updated_at": "2020-11-29T02:54:23.442Z", "provider": "email", "uid": "example222@example.com" } }