Content-Disposition ヘッダーを探しています。次のように応答に含めます。
Content-Disposition: attachment; filename=error.csv
Web ブラウザーは、応答本文をダウンロードするファイルとして扱います (この例では "error.csv" に)。
ただし、これを行うためにコードを変更すると、次の 2 つの点で複雑になります。
Grape のソース コードから、エラー フォーマッタ内から応答ヘッダーを設定する方法がないことは明らかです。そのため、応答本文をフォーマットし、サポートする予定の出力形式ごとに応答ヘッダーを適切に設定するカスタム例外ハンドラーを追加する必要があります。 .
私の実験によると、HTTP ステータス コードがエラー (400 または 500 の範囲内のものなど) を示している場合、ブラウザーは Content-Disposition ヘッダーを無視するため、ユーザーが CSV ファイルを要求したときにステータス コードもオーバーライドする必要があります。
これを API クラスに追加してみてください。
# Handle all exceptions with an error response appropriate to the requested
# output format
rescue_from :all do |e|
# Edit this hash to override the HTTP response status for specific output
# formats
FORMAT_SPECIFIC_STATUS = {
:csv => 200
}
# Edit this hash to add custom headers specific to each output format
FORMAT_SPECIFIC_HEADERS = {
:csv => {
'Content-Disposition' => 'attachment; filename=error.csv'
}
}
# Get the output format requested by the user
format = env['api.format']
# Set the HTTP status appropriately for the requested output format and
# the error type
status = FORMAT_SPECIFIC_STATUS[format] ||
(e.respond_to? :status) && e.status ||
500
# Set the HTTP headers appropriately for the requested format
headers = {
'Content-Type' => options[:content_types][format] || 'text/plain'
}.merge(FORMAT_SPECIFIC_HEADERS[format] || { })
# Format the message body using the appropriate error formatter
error_formatter =
options[:error_formatters][format] || options[:default_error_formatter]
body = error_formatter.call(e.message, nil, options, env)
# Return the error response to the client in the correct format
# with the correct HTTP headers for that format
Rack::Response.new(body, status, headers).finish
end
ここで、2 つの異なる形式を処理するように API クラスを構成すると (ここでは簡単にするために CSV とプレーンテキストを選択しました)、次のようになります。
module Errors
module CSVErrorFormatter
def self.call(message, backtrace, options, env)
as_csv = "CSV formatter:" + "\n"
message.split(",").each do |msg|
as_csv += msg + "\n"
end
# Note this method simply returns the response body
as_csv
end
end
module TextErrorFormatter
def self.call(message, backtrace, options, env)
as_txt = "Text formatter:" + "\n"
message.split(",").each do |msg|
as_txt += msg + "\n"
end
as_txt
end
end
end
content_type :csv, 'text/csv'
content_type :txt, 'text/plain'
error_formatter :csv, Api::Base::Errors::CSVErrorFormatter
error_formatter :txt, Api::Base::Errors::TextErrorFormatter
API は常に、要求された形式に適したエラー応答を返し、CSV 形式が要求された場合にのみブラウザーをトリガーして応答をダウンロードすることがわかります。もちろん、コンテンツ タイプとエラー フォーマッタを明示的に宣言することで、これを拡張して好きなだけ多くのフォーマットをサポートできます。
このコードが自動的に正しいことをしないerror!
ケースが 1 つあります。それは、 を使用してエラー応答が直接呼び出された場合です。その場合、呼び出し自体の一部として正しい本文とヘッダーを指定する必要があります。上記のコードの関連部分を再利用可能なメソッドに抽出することは、読者の演習として残します。