takashi kono's blog

コーヒーとキーボードと共に何かを記録していくブログ

How to use the Rails API

目的

  • Rails API の勉強
  • 備忘録
  • 本当は API Client を Ruby で作ってみたかった

Vagrant up

環境をまっさらに戻せるように Vagrant up で作っていく。
Vagrant up が出来る環境を作るのは、機種依存もあるので、割愛します。

とはいえ参考情報として、私の環境を晒すと、、、

$ cat /etc/issue
Ubuntu 14.04.5 LTS \n \l

$ uname -a
Linux takashi-desktop 3.13.0-123-generic #172-Ubuntu SMP Mon Jun 26 18:04:35 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

$ vagrant -v
Vagrant 1.9.5

$ git --version
git version 2.13.0

$ VBoxManage -v
5.1.22r115126

立ち上げよう

参考

app.vagrantup.com

vagrant init ubuntu/xenial64

出来上がった、 Vagrantfile を編集して、 public network が使えるようにしよう。
下記一文をコメントイン

config.vm.network "public_network"

で、起動

vagrant up

Ruby をインストール

Ruby をインストールしていく

ホストにログイン

vagrant ssh

しなくてもいいが、バージョン確認

ubuntu@ubuntu-xenial:~$ cat /etc/issue
Ubuntu 16.04.3 LTS \n \l

ubuntu@ubuntu-xenial:~$ git --version
git version 2.7.4
ubuntu@ubuntu-xenial:~$ 
# Fix バージョンぽい

Git 脆弱性対応情報
USN-3387-1: Git vulnerability | Ubuntu

rbenv をインストール

ここを参考

https://github.com/rbenv/rbenv#installation

ubuntu@ubuntu-xenial:~$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
ubuntu@ubuntu-xenial:~$ cd ~/.rbenv && src/configure && make -C src
ubuntu@ubuntu-xenial:~/.rbenv$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
ubuntu@ubuntu-xenial:~/.rbenv$ source ~/.bash_profile 
ubuntu@ubuntu-xenial:~/.rbenv$ ~/.rbenv/bin/rbenv init
# Load rbenv automatically by appending
# the following to ~/.bash_profile:

eval "$(rbenv init -)"

ubuntu@ubuntu-xenial:~/.rbenv$ 
ubuntu@ubuntu-xenial:~/.rbenv$ type rbenv
rbenv is /home/ubuntu/.rbenv/bin/rbenv
ubuntu@ubuntu-xenial:~/.rbenv$ 

ruby-build をインストール

ubuntu@ubuntu-xenial:~/.rbenv$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
ubuntu@ubuntu-xenial:~/.rbenv$ rbenv 
rbenv 1.1.1-2-g615f844
Usage: rbenv <command> [<args>]

Some useful rbenv commands are:
   commands    List all available rbenv commands
   local       Set or show the local application-specific Ruby version
   global      Set or show the global Ruby version
   shell       Set or show the shell-specific Ruby version
   install     Install a Ruby version using ruby-build
   uninstall   Uninstall a specific Ruby version
   rehash      Rehash rbenv shims (run this after installing executables)
   version     Show the current Ruby version and its origin
   versions    List all Ruby versions available to rbenv
   which       Display the full path to an executable
   whence      List all Ruby versions that contain the given executable

See `rbenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/rbenv/rbenv#readme
ubuntu@ubuntu-xenial:~/.rbenv$ 

これで、rbenv install コマンドが使えるようになった。

Ruby 2.3.1 をインストール

ubuntu@ubuntu-xenial:~/.rbenv$ rbenv install -l | grep 2.3.1
  2.3.1
ubuntu@ubuntu-xenial:~/.rbenv$ rbenv install 2.3.1
Downloading ruby-2.3.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.bz2
Installing ruby-2.3.1...

BUILD FAILED (Ubuntu 16.04 using ruby-build 20170726-2-g254728e)

Inspect or clean up the working tree at /tmp/ruby-build.20170821144450.9867
Results logged to /tmp/ruby-build.20170821144450.9867.log

Last 10 log lines:
The Ruby openssl extension was not compiled.
The Ruby readline extension was not compiled.
The Ruby zlib extension was not compiled.
ERROR: Ruby install aborted due to missing extensions
Try running `apt-get install -y libssl-dev libreadline-dev zlib1g-dev` to fetch missing dependencies.

Configure options used:
  --prefix=/home/ubuntu/.rbenv/versions/2.3.1
  LDFLAGS=-L/home/ubuntu/.rbenv/versions/2.3.1/lib 
  CPPFLAGS=-I/home/ubuntu/.rbenv/versions/2.3.1/include 
ubuntu@ubuntu-xenial:~/.rbenv$ 

# error が出てビルドが止まった。
# Try running を実施してみる。

ubuntu@ubuntu-xenial:~/.rbenv$ sudo apt-get install -y libssl-dev libreadline-dev zlib1g-dev
ubuntu@ubuntu-xenial:~/.rbenv$ rbenv install 2.3.1
Downloading ruby-2.3.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.bz2
Installing ruby-2.3.1...
Installed ruby-2.3.1 to /home/ubuntu/.rbenv/versions/2.3.1

ubuntu@ubuntu-xenial:~/.rbenv$ 
ubuntu@ubuntu-xenial:~/.rbenv$ ruby -v
The program 'ruby' is currently not installed. You can install it by typing:
sudo apt install ruby
ubuntu@ubuntu-xenial:~/.rbenv$ rbenv which ruby
/home/ubuntu/.rbenv/versions/2.3.1/bin/ruby
ubuntu@ubuntu-xenial:~/.rbenv$ vim ~/.bash_profile 
ubuntu@ubuntu-xenial:~$ cat ~/.bash_profile 
ruby="$HOME/.rbenv/versions/2.3.1/bin/"
export PATH="$HOME/.rbenv/bin:${ruby}:$PATH"
ubuntu@ubuntu-xenial:~$ 
ubuntu@ubuntu-xenial:~/.rbenv$ source ~/.bash_profile
ubuntu@ubuntu-xenial:~$ echo $PATH
/home/ubuntu/.rbenv/bin:/home/ubuntu/.rbenv/versions/2.3.1/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ubuntu@ubuntu-xenial:~$ 
ubuntu@ubuntu-xenial:~$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
ubuntu@ubuntu-xenial:~$ 

あまりイケてないけど、Ruby が使えるようになった。

RailsAPI モードで動かす

Rails をインストールして、API モードでアプリを作る。

インストール

gem update --system
gem install rails

これで、Rails のインストール完了

API モードでアプリケーションを作る

ubuntu@ubuntu-xenial:~$ rails new railsapimode --api
...
checking for sqlite3.h... no
sqlite3.h is missing. Try 'brew install sqlite3',
'yum install sqlite-devel' or 'apt-get install libsqlite3-dev'
and check your shared library search path (the
location where your sqlite3 shared library is located).
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

どうやら、sqlite3.h が無い様子。
書いてあるとおり、コマンドを実行する。

ubuntu@ubuntu-xenial:~$ sudo apt-get install libsqlite3-dev
ubuntu@ubuntu-xenial:~$ rails new railsapimode --api
ubuntu@ubuntu-xenial:~$ rails -v
Rails 5.1.3
ubuntu@ubuntu-xenial:~$ 

上手くインストールできたようだ。

API の作成

ubuntu@ubuntu-xenial:~$ cd railsapimode/
ubuntu@ubuntu-xenial:~/railsapimode$ rails g scaffold Users name:string age:integer org:string sex:string
Running via Spring preloader in process 24106
[WARNING] The model name 'Users' was recognized as a plural, using the singular 'User' instead. Override with --force-plural or setup custom inflection rules for this noun before running the generator.
      invoke  active_record
      create    db/migrate/20170821162126_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
ubuntu@ubuntu-xenial:~/railsapimode$ 

作れた。

users_controller.rb を確認する

ubuntu@ubuntu-xenial:~/railsapimode$ cat app/controllers/users_controller.rb 
class UsersController < ApplicationController
  before_action :set_user, only: [:show, :update, :destroy]

  # GET /users
  def index
    @users = User.all

    render json: @users
  end

  # GET /users/1
  def show
    render json: @user
  end

  # POST /users
  def create
    @user = User.new(user_params)

    if @user.save
      render json: @user, status: :created, location: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /users/1
  def update
    if @user.update(user_params)
      render json: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

  # DELETE /users/1
  def destroy
    @user.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def user_params
      params.require(:user).permit(:name, :age, :org, :sex)
    end
end
ubuntu@ubuntu-xenial:~/railsapimode$ 

見てわかるとおり、GET や POST など、メソッドおよびアクセスするときの解説付きて展開される。

seed ファイルに、サンプルデータを入れる

ubuntu@ubuntu-xenial:~/railsapimode$ vim db/seeds.rb 
ubuntu@ubuntu-xenial:~/railsapimode$ cat db/seeds.rb 
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
#
# Examples:
#
#   movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
#   Character.create(name: 'Luke', movie: movies.first)
User.create(name: 'user1', age: 21, org: 'section 1', sex: 'man')
User.create(name: 'user2', age: 22, org: 'section 2', sex: 'man')
User.create(name: 'user3', age: 23, org: 'section 3', sex: 'woman')
User.create(name: 'user4', age: 21, org: 'section 1', sex: 'woman')

ubuntu@ubuntu-xenial:~/railsapimode$ 

migrate とか

rails db:migrate
rails db:seed
rails s

curl で動作確認

別端末を起動して、vagrant sshで中に入る。

curl でテスト。

# User 一覧の取得
ubuntu@ubuntu-xenial:~$ curl -sv -H 'Content-Type' http://localhost:3000/users -X GET -w '\n\n'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /users HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< ETag: W/"718134f3ca6a612c64c9c16753883eb6"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 8f0511f4-f726-44d6-a993-0d0765bd5d71
< X-Runtime: 0.263571
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
[{"id":1,"name":"user1","age":21,"org":"section 1","sex":"man","created_at":"2017-08-21T16:27:44.054Z","updated_at":"2017-08-21T16:27:44.054Z"},{"id":2,"name":"user2","age":22,"org":"section 2","sex":"man","created_at":"2017-08-21T16:27:44.061Z","updated_at":"2017-08-21T16:27:44.061Z"},{"id":3,"name":"user3","age":23,"org":"section 3","sex":"woman","created_at":"2017-08-21T16:27:44.065Z","updated_at":"2017-08-21T16:27:44.065Z"},{"id":4,"name":"user4","age":21,"org":"section 1","sex":"woman","created_at":"2017-08-21T16:27:44.070Z","updated_at":"2017-08-21T16:27:44.070Z"}]

ubuntu@ubuntu-xenial:~$ 

# User の情報を取得
ubuntu@ubuntu-xenial:~$ curl -sv -H 'Content-Type' http://localhost:3000/users/1 -X GET -w '\n\n'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /users/1 HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< ETag: W/"bfda4451a19a000f8bd9e150b9d23aa1"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 9e51b1e8-5ba7-4b81-a8c3-761c94dd41f8
< X-Runtime: 0.015374
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
{"id":1,"name":"user1","age":21,"org":"section 1","sex":"man","created_at":"2017-08-21T16:27:44.054Z","updated_at":"2017-08-21T16:27:44.054Z"}

ubuntu@ubuntu-xenial:~$ 

# User を作成
ubuntu@ubuntu-xenial:~$ curl -sv -H 'Content-Type: application/json' -d '{ "user" : { "name": "user5", "age":25, "org":"section2", "sex":"woman" } }' http://localhost:3000/users -X POST -w '\n\n'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> POST /users HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 75
> 
* upload completely sent off: 75 out of 75 bytes
< HTTP/1.1 201 Created
< Location: http://localhost:3000/users/5
< Content-Type: application/json; charset=utf-8
< ETag: W/"e8248c5cbf259acf172667196f403545"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 33be92f3-532d-40f2-84a8-ceb5c7e39467
< X-Runtime: 0.017082
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
{"id":5,"name":"user5","age":25,"org":"section2","sex":"woman","created_at":"2017-08-21T16:40:20.840Z","updated_at":"2017-08-21T16:40:20.840Z"}

ubuntu@ubuntu-xenial:~$ 

# User を更新
ubuntu@ubuntu-xenial:~$ curl -sv -H 'Content-Type: application/json' -d '{ "user" : { "org":"section 4" } }' http://localhost:3000/users/5 -X PUT -w '\n\n'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> PUT /users/5 HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 34
> 
* upload completely sent off: 34 out of 34 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< ETag: W/"3d2c91c68c4e49004e3cbb79f62d2dea"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 576329f0-7792-402c-a950-5de647ee22a0
< X-Runtime: 0.011775
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
{"id":5,"org":"section 4","name":"user5","age":25,"sex":"woman","created_at":"2017-08-21T16:40:20.840Z","updated_at":"2017-08-21T16:43:29.569Z"}

ubuntu@ubuntu-xenial:~$ 

# User を削除
ubuntu@ubuntu-xenial:~$ curl -sv -H 'Content-Type: application/json' http://localhost:3000/users/5 -X DELETE -w '\n\n'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> DELETE /users/5 HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Type: application/json
> 
< HTTP/1.1 204 No Content
< Cache-Control: no-cache
< X-Request-Id: 3b51886b-3d78-40d4-8d0e-b7eb676259e2
< X-Runtime: 0.015196
< 
* Connection #0 to host localhost left intact


ubuntu@ubuntu-xenial:~$ 

# 存在しないUserを取得
ubuntu@ubuntu-xenial:~$ curl -sv -H 'Content-Type: application/json' http://localhost:3000/users/0 -X GET -w '\n\n'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /users/0 HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Type: application/json
> 
< HTTP/1.1 404 Not Found
< Content-Type: application/json; charset=UTF-8
< X-Request-Id: b1d90e0b-61e2-4e14-827a-aa3fc6dc4d76
< X-Runtime: 0.037391
< Content-Length: 10812
< 
{"status":404,"error":"Not Found"
...



次回は、このAPI modeを利用して、API Clientを作ってみたいと思います。
(基礎すっ飛ばしているから、もう一度復習しよう)

以上。