RailsでバックエンドのAPIをつくる。ついでにユーザー認証も

バックエンドのAPIが出来てなくて、フロントの開発がなかなか進まないなんてことはよくある話ですよね。

そんなときは、RailsでサックッとAPIを作りましょう。というときの手順のメモ。

環境

  • macOS Mojave 10.14.6

  • Rails 5.2.3

  • ruby 2.6.3





gemをrailsプロジェクトごとに管理する

bundle initGemfileを作成

$ mkdir api
$ cd api
$ bundle init 

Gemfileを編集

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'rails', '~> 5.2.3'

次にbundle install --path vendor/bundleを実行。次回からは--path vendor/bundleは不要。

$ bundle install --path vendor/bundle





Rails new apiモード

自分の設定に合わせてオプションを変える。

オプションでデーターベースを変更できたりしますが、モック用なのでデフォルトのSQLiteで十分。

$ bundle exec rails new . --api -B 





ユーザー認証のapiを作成する

ユーザー認証のapi作成には、Devise Token Authを使います。

devise_token_auth

公式ドキュメント





Gemfileの設定

# Gemfile

# devise関連
gem 'devise'
gem 'devise_token_auth'

# CORS設定
gem 'rack-cors'

rack-corsでCORSの設定をする必要があるので、config/cors.rbのコメントを外し、以下のようにします。

# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.

# Read more: https://github.com/cyu/rack-cors

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'example.com'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

ここまで終わったらbundleとデータベースを作成します。

$ bundle install
$ bundle exec rake db:create





devise token auth の導入

$ bundle exec rails g devise:install
$ bundle exec rails g devise_token_auth:install User auth

次にデフォルトで作成されたマイグレーションファイルdevise_token_auth_create_users.rbを以下のように変更します。

class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[5.2]
  def change
    
    create_table(:users) do |t|
      ## Required
      t.string :provider, :null => false, :default => "email"
      t.string :uid, :null => false, :default => ""

      ## Database authenticatable
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at
      t.boolean  :allow_password_change, :default => false

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## User Info
      t.string :name
      t.string :nickname
      t.string :image
      t.string :email

      ## Tokens
      t.text :tokens

      t.timestamps
    end

    add_index :users, :email,                unique: true
    add_index :users, [:uid, :provider],     unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,       unique: true
  end
end

devise token auth の設定。

# config/initializers/devise_token_auth.rb

# frozen_string_literal: true

DeviseTokenAuth.setup do |config|
  # By default the authorization headers will change after each request. The
  # client is responsible for keeping track of the changing tokens. Change
  # this to false to prevent the Authorization header from changing after
  # each request.
  config.change_headers_on_each_request = false

  # By default, users will need to re-authenticate after 2 weeks. This setting
  # determines how long tokens will remain valid after they are issued.
  config.token_lifespan = 2.weeks

  # Limiting the token_cost to just 4 in testing will increase the performance of
  # your test suite dramatically. The possible cost value is within range from 4
  # to 31. It is recommended to not use a value more than 10 in other environments.
  config.token_cost = Rails.env.test? ? 4 : 10

  # Sets the max number of concurrent devices per user, which is 10 by default.
  # After this limit is reached, the oldest tokens will be removed.
  # config.max_number_of_devices = 10

  # Sometimes it's necessary to make several requests to the API at the same
  # time. In this case, each request in the batch will need to share the same
  # auth token. This setting determines how far apart the requests can be while
  # still using the same auth token.
  # config.batch_request_buffer_throttle = 5.seconds

  # This route will be the prefix for all oauth2 redirect callbacks. For
  # example, using the default '/omniauth', the github oauth2 provider will
  # redirect successful authentications to '/omniauth/github/callback'
  # config.omniauth_prefix = "/omniauth"

  # By default sending current password is not needed for the password update.
  # Uncomment to enforce current_password param to be checked before all
  # attribute updates. Set it to :password if you want it to be checked only if
  # password is updated.
  # config.check_current_password_before_update = :attributes

  # By default we will use callbacks for single omniauth.
  # It depends on fields like email, provider and uid.
  # config.default_callbacks = true

  # Makes it possible to change the headers names
  config.headers_names = {:'access-token' => 'access-token',
                         :'client' => 'client',
                         :'expiry' => 'expiry',
                         :'uid' => 'uid',
                         :'token-type' => 'token-type' }

  # By default, only Bearer Token authentication is implemented out of the box.
  # If, however, you wish to integrate with legacy Devise authentication, you can
  # do so by enabling this flag. NOTE: This feature is highly experimental!
  # config.enable_standard_devise_support = false
end

最後に、apiを使うときにCSRFチェックに引っかかるので、application_controllerを以下のようにします。

class ApplicationController < ActionController::API
        skip_before_action :verify_authenticity_token, if: :devise_controller?, raise: false 
        include DeviseTokenAuth::Concerns::SetUserByToken
end





ユーザーを作成する

サーバーを立ち上げて、試しにユーザーを作成してみましょう。

$ curl localhost:3000/auth -X POST -d '{"email":"example@example.com", "password":"password", "password_confirmation": "password"}' -H "content-type:application/json"

ルーティングエラーが出たらルーティングに間違いがないか、http://localhost:3000/rails/info/routesで確認しましょう。

ちゃんとユーザーが作成されているか確認する。

irb(main):001:0> User.all
  User Load (0.5ms)  SELECT  "users".* FROM "users" LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, provider: "email", uid: "example@example.com", allow_password_change: false, name: nil, nickname: nil, image: nil, email: "example@example.com", created_at:
 "2019-09-02 01:17:32", updated_at: "2019-09-02 01:17:32">]>

ちゃんとできてました。

See Also