RailsのAPIモードを試してみた話

RailsAPIモードを試してみた話

はじめに

これは香川大学工学部サークルSLPのアドベントカレンダー14日目の記事です。 前後、怖い人に挟まれていますが頑張ります(ガクブル)。 今回はRails5から実装されたAPIモードを使ってAPIサーバを構築し、様々な言語でHTTPリクエストを送ってみたいと思います。 かなり緩くやっていけたらなと思います。

APIモードとは

API作成に特化したモードのことで、Rails5で実装された機能らしいです。 簡単に今までのRailsとの違いを説明すると、MVCでいう、Viewの部分が存在しません。 変わりにそのURLにアクセスするとerbを返さず、jsonを返す仕様になっています。 また、標準で入っているGemもViewの分が必要なくなっているので、普通に立ち上げたRailsのプロジェクトよりも少なくなっています。 詳しくは各々で調べてみてください。

とりあえず使ってみた

さっそくですが、RailsAPIモードを使って、APIサーバを構築してみたいと思います。 今回は名前と学籍番号を管理するAPIを構築してみます。

今回使用した開発環境をざっくり紹介するとこんな感じです。
- Ubuntu16.04
- Ruby 2.4.1
- Rails 5.1.4

それではまず、プロジェクトを立ち上げます。

Rails new name_api --api

プロジェクト名の後に、 --apiをつけることでAPIモードでプロジェクトが立ち上がります。 --apiをつけなければ今まで通りのRailsのプロジェクトとして立ち上がります(当たり前)。 では、プロジェクトの中に入ってみましょう。

cd name_api

Railsらしく、様々なディレクトリとファイルが生成されていると思います。 今回は手早くRESTfulなAPIを作りたいのでscaffoldを使います。 基本的にはAPIモードでもRailsのコマンドは同じように使えるみたいです。 それでは、コマンドを入力していきます。

rails g scaffold User name:string number:string

ずらーっと色々と表示されたと思います。createとかinvokeとかrouteが出てきて、正常に終わっていればOKです。 私側の実行では、以下のように表示されました。

Running via Spring preloader in process 19815
      invoke  active_record
      create    db/migrate/20171205074009_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

そしてmigrateします。

rails db:create && rails db:migrate

これでAPI側の実装はほとんど終わりです(すごく簡単!!)。 それではサーバを立ち上げてみましょう。

rails server -b=0.0.0.0

無事に起動したら、アクセスしてみます。

http://localhost:3000

アクセスできたら、いつものRailsのページが表示されると思います。

ルーティングを確認

以下のコマンドを入力して、ルーティングを確認します。

rails routes

以下のように表示されていると思います。

Prefix Verb   URI Pattern          Controller#Action
 users GET    /users(.:format)     users#index
       POST   /users(.:format)     users#create
  user GET    /users/:id(.:format) users#show
       PATCH  /users/:id(.:format) users#update
       PUT    /users/:id(.:format) users#update
       DELETE /users/:id(.:format) users#destroy

ためしに、users#indexにアクセスしてみます。

http://localhost:3000/users

通常、scaffoldを使うとあらかじめ完成されたページが表示されると思います。しかし、今回の場合だと、 [ ] だけが表示されたと思います。 なぜかというと、controllerを見ればわかりますが、APIモードでは、erbではなく、JSONを返してくれているからなのです。 [ ] なのは、まだ何もレコードされていないからですね。

様々な方法でPOSTしてみる

それでは、このAPIにPOSTリクエストを送ってみます。 基本的にはHTTPリクエストで、JSONをPOSTしてあげればOKです。 POSTするURLは先ほど確認したのでそれに従います。 今回の場合であれば以下のURLにPOSTしてあげればよさそうです。

http://localhost:3000/users

curlでPOST

curl -X POST -H "Content-Type: application/json" -d '{"name": "明示カール", "number": "17t200"}' http://localhost:3000/users

RubyでPOST

post.rb

require 'net/http'
require 'uri'
require 'json'

url = "http://localhost:3000/hoges"
sample_data = {"name": "白沢ルビィ" : "number": "16t200"}

uri = URI.parse(url)

http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.request_uri)
req["Content-Type"] = "application/json"
req.body = sample_data.to_json
res = http.request(req)

Python3でPOST

post.py

import requests
import json

url = 'http://localhost:3000/hoges'
method = "POST"
obj = {"name" : "本田パイソン", "number": "15t200"}
json_data = json.dumps(obj).encode("utf-8")

response = requests.post(url, json.dumps(obj), headers = {'Content-Type' : 'application/json'})
print(response.text)

JavaScriptでPOST

JavaScriptでPOSTする場合API側の設定を少し変更してあげなければなりません。 変更点は以下の記事を参考にしてみてください。 https://qiita.com/kaorumori/items/0a53c248343892c8f35c

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>JavaScriptからPOSTでJSONデータを送信する</title>
    <script src="jquery.js"></script>
    <script src="post.js"></script>
  </head>
  <body>
    <p>
      URL: <input type="text" id="url_post" name="url" size="100" value="http://localhost:3000/users">
    </p>
    <p>
      name:<input type="text" id="name" size="30" value="じゃばすく太郎">
    </p>
    <p>
      number:<input type="text" id="number" size="30" value="13T200">
    </p>
    <p>
      <button id="button" type="button">Submit</button></p>
    </p>
  </body>
</html>

post.js

$(function(){
  $("#response").html("Response Value");

  $("#button").click( function(){
    const url = $("#url_post").val();

    const JSONdata = {
      name: $("#name").val(),
      number: $("#name").val()
    };

    alert(JSON.stringify(JSONdata));

    $.ajax({
      type : 'post',
      url : url,
      data : JSON.stringify(JSONdata),
      contentType : 'application/JSON',
      dataType : 'JSON',
      scritCharset : 'utf-8',
      succes : function(data) {
        alert("success");
        alert(JSON.stringify(data));
        $("#response").html(JSON.stringify(data));
      },
      error : function(data) {
        alert("error");
        alert(JSON.stringify(data));
        $("#response").html(JSON.stringify(data));
      }
    });
  });
});

今回のサンプルコードでは、jqueryを使用しました。 今回の場合ですと、jqeuryをjquery.jsとして同じ階層のディレクトリに置いておいてあげて解決しています。

POSTしたデータを確認してみる

それでは先ほど、POSTしたデータを確認してみましょう。 まずはすべてのPOSTしたすべてのデータを確認してみます。

http://localhost:3000/users

上記のURLにアクセスすると、先ほどと違いPOSTした内容がレコードされていると思います。 せっかくなのでGETリクエストを送ってデータを取得してみます。 今回は、手っ取り早くcurlを使います。

curl http://localhost:3000/users

取得したのがこちら。

[{"id":1,"name":"明示カール","number":"17t200","created_at":"2017-12-05T08:15:37.735Z","updated_at":"2017-12-05T08:15:37.735Z"},{"id":2,"name":"白沢ルビィ","number":"16t200","created_at":"2017-12-05T14:51:40.472Z","updated_at":"2017-12-05T14:51:40.472Z"},{"id":3,"name":"本田パイソン","number":"15t200","created_at":"2017-12-05T14:52:46.918Z","updated_at":"2017-12-05T14:52:46.918Z"},{"id":4,"name":null,"number":"じゃばすく太郎","created_at":"2017-12-05T15:00:04.685Z","updated_at":"2017-12-05T15:00:04.685Z"}]

created_atやupdated_atは違う値を保持しているはずですが、似たようなデータを取得できたと思います。 次にレコードしたデータを一つずつ取得してみます。 試しに1番目と2番目のデータを取得してみます。 1番目

curl http://localhost:3000:users/1
{"id":1,"name":"明示カール","number":"17t200","created_at":"2017-12-05T08:15:37.735Z","updated_at":"2017-12-05T08:15:37.735Z"}%

2番目

curl http://localhost:3000:users/2
{"id":2,"name":"白沢ルビィ","number":"16t200","created_at":"2017-12-05T14:51:40.472Z","updated_at":"2017-12-05T14:51:40.472Z"}%

いい感じに取得できました。

まとめ

雑な説明になってしまいましたがいかかだったでしょうか。 いろいろな部分の説明を省いているので、詳しく知りたい方はこの記事ををきっかけにAPIモードについて調べてもらえたらなと思います。 私自身は、今後このモードを使って、様々なAPIを作ってみて、それに対応したネイティブアプリやスマホアプリを作ってみたいです。

最後に・・・

この記事で作ったサンプルコードの出来が悪くても、多めにみてやってください...。