Encorda automaticamente a saída do rack com JSON quando o tipo conteúdo é aplicativo/JSON
-
26-09-2019 - |
Pergunta
Eu tenho um aplicativo Sinatra modular e gostaria de codificar a saída como JSON quando o tipo de conteúdo ditar. No momento estou fazendo isso manualmente em minhas rotas:
get 'someroute' do
# content-type is actually set with a before filter
# included only for clarity
content_type 'application/json', :charset => 'utf-8'
# .. #
{:success=>true}.to_json
end
Eu preferiria que pareça assim:
get 'someroute' do
content_type 'application/json', :charset => 'utf-8'
# .. #
{:success=>true}
end
E eu gostaria de usar o middleware do rack para fazer a codificação se ele detectar o tipo de conteúdo apropriado.
Eu tenho tentado fazer com que o seguinte funcione, mas sem sucesso (o comprimento do conteúdo é Borked-retorna o comprimento do conteúdo do conteúdo original e não o conteúdo codificado da JSON):
require 'init'
module Rack
class JSON
def initialize app
@app = app
end
def call env
@status, @headers, @body = @app.call env
if json_response?
@body = @body.to_json
end
[@status, @headers, @body]
end
def json_response?
@headers['Content-Type'] == 'application/json'
end
end
end
use Rack::JSON
MyApp.set :run, false
MyApp.set :environment, ENV['RACK_ENV'].to_sym
run MyApp
Algum indicador para me levar de volta aos trilhos?
Solução
Você tem tudo certo, mas uma coisa: o rack espera que o corpo seja um objeto que responda a each
mas não é uma string. Basta colocar seu corpo dentro de uma matriz.
Provavelmente não é necessário, mas se você deseja definir o comprimento do conteúdo manualmente, basta adicioná -lo aos cabeçalhos.
if json_response?
@body = [@body.to_json]
@headers["Content-Length"] = @body[0].size.to_s
end