3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails / JavaScript】レスポンスのフォーマットをJSONに指定する(.jsonを付加せずに)

Last updated at Posted at 2020-01-28

コントローラーにおけるJSONフォーマットの指定

JavaScriptのみでAjaxを書く際に、レスポンスデータをJSONで受け取ることに苦労したので、備忘として書いておきます。

使用しているフレームワークは、Ruby on Raisです。
具体的には、次のようなコントローラーのrespond_toメソッドにおいて、format.jsonを選択させることが目的になります。

messages_controller.rb
def create
  @message = Message.new(message_params)
  if @message.save
    respond_to do |format|
      format.html { redirect_to root_path }
      format.json { render json: { text: @message.text, id: @message.id } }
    end
  end
end

この記事の結論を先に言うと、Acceptリクエストヘッダでレスポンスのフォーマットを指定するということになります(後述)。
分かっている方には、当たり前の内容かもしれません。

<実行した環境>
Rails 5.2.4.1
Ruby 2.5.1
(turbolinksは無効にしています)

一般的な指定の方法

まずは、一般的な指定の方法です。普通はこれで解決すると思います。

jQueryの場合

jQueryでは、dataType: "json"の1行を入れれば、JSONフォーマットを指定できます。

jQueryの例
$.ajax({
  url: "/messages",
  type: "POST",
  data: {
    message: {text: "hoge"}
  },
  dataType: "json"  // レスポンスフォーマットをjson形式と指定する
})

JavaScriptの例(.jsonを付加する場合)

JavaScriptでは、次のように、open()メソッドのURL指定(第2引数)のところで"/messages.json"とします。

JavaScriptの例(.jsonを付加)
xmlHttpRequest.open("POST", "/messages.json");  // urlの末尾に.jsonを付加することでレスポンスフォーマットを指定
xmlHttpRequest.responseType = "json";  // レスポンスデータの形式をjsonと指定(これはフォーマットの指定ではない)
xmlHttpRequest.setRequestHeader("Content-Type", "application/json");
xmlHttpRequest.setRequestHeader("X-CSRF-Token", token);
xmlHttpRequest.send(data);

このように、リクエストURLの末尾に.jsonを付加すれば、JSONのフォーマットでレスポンスを得ることができます。
なお、サンプルコードの全体像を確認されたい場合は、RailsにおけるAjaxの実装を参照してください。

<勘違いしていたところ>
2行目のresponseTypeメソッドで、xmlHttpRequest.responseType = "json"というように指定していますが、最初は、これをレスポンスのフォーマットの指定と勘違いしていました。

確認してみると、"json"と指定した場合のレスポンスデータは、{text: "hoge", id: 3}という形式で戻り、指定しなかった場合には、{"text":"hoge","id":3}という形で戻ってくるだけです。
つまり、responseTypeメソッドはフォーマットを指定するものではないということです。

リクエストヘッダで指定する方法

最後に、リクエストURLに、.jsonを付加しないでレスポンスのフォーマットを指定する方法です。

リクエストヘッダに次の1行を追加すれば、JSONのフォーマットでレスポンスデータが届きます。

RequestHeaders
Accept: application/json

このAcceptリクエストヘッダは、クライアントが理解できるコンテンツタイプ(MIMEタイプ)をサーバに伝えるものです(参照情報:MDN Web Docs / Accept)。

jQueryのリクエストヘッダに、上記の指定がされていたことから、JavaScriptでも同様の指定をすることでうまく動作しました。

このリクエストヘッダを追加するには、JavaScriptに次の1行を入れます。

xmlHttpRequest.setRequestHeader("Accept", "application/json");

念のため、コードの全体像を示せば次のとおりです。
リクエストURLへの.jsonの付加は不要となります。

sample.js
window.addEventListener("load", function() {
  let token = document.getElementsByName("csrf-token")[0].content; //セキュリティトークンの取得
  document.getElementById("nmessage_input").addEventListener("submit", function(e) {
    e.preventDefault();
    let hashData = { message: { text: "hoge" } };
    let data = JSON.stringify(hashData);
    let xmlHttpRequest = new XMLHttpRequest();  // XMLHttpRequestオブジェクトの作成
    xmlHttpRequest.open("POST", "/messages");  // urlの末尾への.jsonの付加は不要
    xmlHttpRequest.responseType = "json";
    xmlHttpRequest.setRequestHeader("Accept", "application/json");  // リクエストヘッダーを追加(クライアントが理解できるコンテンツタイプをサーバに通知)
    xmlHttpRequest.setRequestHeader("Content-Type", "application/json");  // リクエストヘッダーを追加(リクエストをJSONで送信する旨)
    xmlHttpRequest.setRequestHeader("X-CSRF-Token", token);  // リクエストヘッダーを追加(セキュリティトークンの追加)
    xmlHttpRequest.send(data);  // sendメソッドでサーバに送信
    xmlHttpRequest.onreadystatechange = function() {
      if (xmlHttpRequest.readyState === 4) {
        if (xmlHttpRequest.status === 200) {
          // リクエストが成功した場合の処理を記載
        } else {
          // リクエストが失敗した場合の処理を記載
        }
      }
    };
  });
});

以上です。
何らかのお役にたてば幸いです。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?