APIとは
必要なデータだけをJSONなどの形式で返すサーバの仕組みのことをAPI、もしくはJSON APIと呼ぶ。
webAPI
json形式で情報をレスポンスするアクションはwebAPIと言われる。
railsではWebAPIにあたるアクションを書くコントローラのファイルは全てapiというディレクトリに置くルール。
コントローラにAPIフォルダを作成し、API化するコントローラのrbファイルを作成。
例
app/controllers/api/messages_controller.rb
同様にviewファイルもフォルダを作成してから作成
例
app/views/api/index.json.jbuilder
APIの作り方(rails)
- HTMLを返すためのコントローラーを共用してAPIとして使えるようにする
- API専用のコントローラーを作成する
- APIを作成するためのgemを利用する
コントローラーでの振り分け
Railsには、コントローラーのアクションの中でHTMLとJSONといったフォーマット毎に条件分岐できる仕組みがある。
respond_to
コントローラーで利用できる。
JSONを返す場合はRubyのハッシュの状態のままrenderメソッドに渡すだけでJSONに変換してくれる。インスタンス単体ならそのまま渡してもOK。
respond_to do |format|
format.html { render ... } # この中はHTMLリクエストの場合に呼ばれる
format.json { render ... } # この中はJSONリクエストの場合に呼ばれる
end
respond_to do |format|
format.json {
render json: { id: @user.id, name: @user.name }
}
end
def create
@todo = Todo.new(todo_params)
if @todo.save
respond_to do |format|
format.html { redirect_to :root }
format.json { render json: @todo}
end
else
render :index
end
end
ルーティングで振り分け
defaultオプションを用いてアクセスされた場合に常にjsonを返すようにも設定できる。
返却されるjson形式のデータ
インスタンスを渡すとそのモデルの情報のみがjson内に格納される。
format.json {render json: @message}
この場合jQuery側で@messageのインスタンス変数は呼べるが、アソシエーションを組んだモデル@message.userは呼べない。
なので@message.user.nameが欲しい時はインスタンスを投げるのではなく、json.jbuilderファイル内で以下のように別途定義してjsonのviewを返す。
json.body @message.body
json.name @message.user.name
jbuilder
rails newした際にgemfileにデフォルトで記述されているgem。
入力データをJSON形式で出力するテンプレートエンジン。
jbuilderを使用してJavaScriptファイルに返すデータを作成
viewを同じように該当するアクションと同じ名前にする必要がある。
viewと同じように該当コントローラの該当アクション名で.json.jbuilderファイルを作成する。
例
hogehoges_controllerの#createアクションに対応するjbuilderファイルを
view/hogehoges/create.json.builderに作成する。
json.jbuilderファイル内の記法
基本的にjson.KEY VALUEと記述する。
この時のkeyを用いてJavaScriptでDOM要素に出力する。
json.text @comment.text
json.user_id @comment.user.id
json.user_name @comment.user.nickname
以下のようにインスタンスを渡してまとめて定義することもできる。
json.(@message, :content, :image)
ちなみにcontroller側の記述で
@comment = Comment.new(params) とせずに
comment = Comment.new(params)
@抜きにした場合、
json.jbuilderファイル内でjson.text comment.textのように記述しても出力できない。
newは通るけれど、viewに投げるには@が符号になっているためこのような処理は通らない。
viewファイルを経由せずにcontroller側でハッシュにしてしまえば通る。
これは通る
@comment = Comment.new()
略
format.json
@をつけない場合。コントローラ内でハッシュにして渡せば通る。
view経由させるなら@は必須。
def create
comment = Comment.create(comment_params)
hoge = {text: comment.text, user_id: comment.user_id }
respond_to do |format|
format.html { redirect_to tweet_path(params[:tweet_id]) }
format.json { render json: hoge}
end
end
json.array!
json形式のデータを配列にしたい場合に使う。
json.array! @products do |product|
json.id product.id
json.title product.title
json.image product.image_url
json.detail product.detail
end
名前空間(namespace)
class Api::MessagesController < ApplicationController
def index
end
end
同名のコントローラ名を使いたい場合、コントローラ名の前に::をつけて別名を付与できる。
名前空間をつけることにより、同名であっても区別できる。
Api::MessagesControllerとする場合には、相当する位置にmessages_controller.rbファイルを置く必要がある。
つまり、controller/api/messages_controller.rbに置く。
名前空間を増やしてディレクトリを深くする場合には、ディレクトリにそった命名が必要。
controller/api/hoge/fuga/messages_controller.rbなら
Api::Hoge::Fuga::MessagesControllerと命名する。
でなければ404not foundとなる。
なお対応するviewファイルはそれより1段深い階層に設置する。
(コントローラの分だけ深くなる)
views/api/messages/index.json.jbuilder
resourcesでnamespaceのネスト
通常通りネストした場合と大きな変化はない。
単にネストの親のidの次にnamespace名を挟むだけ。
resources :groups do
namespace :api do
resources :messages
end
end
group_api_messages GET /groups/:group_id/api/messages(.:format) api/messages#index
POST /groups/:group_id/api/messages(.:format) api/messages#create
new_group_api_message GET /groups/:group_id/api/messages/new(.:format) api/messages#new
edit_group_api_message GET /groups/:group_id/api/messages/:id/edit(.:format) api/messages#edit
group_api_message GET /groups/:group_id/api/messages/:id(.:format) api/messages#show
PATCH /groups/:group_id/api/messages/:id(.:format) api/messages#update
PUT /groups/:group_id/api/messages/:id(.:format) api/messages#update
DELETE /groups/:group_id/api/messages/:id(.:format) api/messages#destroy
resourcesのオプション
formatオプションをつけるとアクセスした際のレスポンスを設定できる。
resources :messages,only: :index, defaults: { format: 'json' }
rake routesすると以下のように変化する。
api/messages#index {:format=>"json"}
Ajax
$.ajax()は以下の4つの要素を送信する。
この要素の記載に続けて、.doneと.failを記載して送信後の処理を行う。
type | HTTP通信の種類を記述する。通信方法は、GETとPOSTの2種類がある。 |
url | リクエストを送信する先のURLを記述する。 |
data | サーバに送信する値を記述する。 |
dataType | サーバから返されるデータの型を指定する。 |
$(function() {
function buildHTML(todo) {
var html = $('<li class="todo">').append(todo.content);
return html;
}
$('.js-form').on('submit', function(e) {
e.preventDefault();
var textField = $('.js-form__text-field');
var todo = textField.val();
$.ajax({
type: 'POST',
url: '/todos.json',
data: {
todo: {
content: todo
}
},
dataType: 'json'
})
.done(function(data) {
var html = buildHTML(data);
$('.todos').append(html);
textField.val('');
})
.fail(function() {
alert('error');
});
});
});
渡すデータ
dataは基本的にハッシュで渡す。
formの場合はハッシュのネストで渡すと通常のフォームと同じ形式になるが、
FormDataオブジェクトで渡すのが普通。
data: { keyword: input },
返ってくるデータ
$.ajax({})
.done(function(DATA){})
$.ajax({})の後の.done(function(DATA){})のDATA部分はajaxでリクエストを投げた結果、返ってきた値が入る。
入れる値を指定しているのではなくて、返ってきた値をDATAと命名し、以降の関数内でDATAという変数名で用いる。
通常の引数を渡すという感覚ではなく、引数はすでに持っていてそれに名前をつける感覚。
リダイレクトするパス
ajax関数のurlに何も指定しなかった場合、リクエストのURLは現在ブラウザに表示されているパスになる。
urlに文字列で値を指定すると、現在ブラウザに表示されているURLの後に繋がる形になる。
“/”を付けるとrootからのパスになる。
http://hogehoge.com/fugaの時
$.ajax{
url: "hoge"
}
とすると
"http://hogehoge.com/fuga/hoge"
へリダイレクトする。
$.ajax{
url: "/hoge"
}
とすると
"http://hogehoge.com/hoge"
へリダイレクトする。
コメント