バックエンドのAPIが出来てなくて、フロントの開発がなかなか進まないなんてことはよくある話ですよね。
そんなときは、RailsでサックッとAPIを作りましょう。というときの手順のメモ。
bundle init
でGemfile
を作成
$ 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
自分の設定に合わせてオプションを変える。
オプションでデーターベースを変更できたりしますが、モック用なのでデフォルトのSQLiteで十分。
$ bundle exec rails new . --api -B
ユーザー認証のapi作成には、Devise Token Auth
を使います。
# 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
$ 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":"[email protected]", "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: "[email protected]", allow_password_change: false, name: nil, nickname: nil, image: nil, email: "[email protected]", created_at:
"2019-09-02 01:17:32", updated_at: "2019-09-02 01:17:32">]>
ちゃんとできてました。