Автоматически кодировать вывод Rack с помощью JSON, когда Content-Type - application / json - PullRequest
3 голосов
/ 06 августа 2010

У меня есть модульное приложение Sinatra, и я хотел бы закодировать вывод как JSON, когда диктует тип содержимого. На данный момент я делаю это вручную в моих маршрутах:

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

Я бы предпочел, чтобы это выглядело так:

get 'someroute' do
    content_type 'application/json', :charset => 'utf-8'
    # .. #
    {:success=>true}
end

И я хотел бы использовать промежуточное программное обеспечение Rack для кодирования, если оно обнаруживает соответствующий тип контента.

Я пытался заставить работать следующее, но безрезультатно (длина содержимого теряется - возвращает длину содержимого исходного содержимого, а не содержимого в кодировке 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

Какие-нибудь указатели, чтобы вернуть меня в нужное русло?

1 Ответ

4 голосов
/ 06 августа 2010

У вас все в порядке, кроме одного: Rack ожидает, что тело будет объектом, который отвечает на each, но не является строкой. Просто поместите свое тело в массив.

Возможно, в этом нет необходимости, но если вы хотите установить длину содержимого вручную, просто добавьте его в заголовки.

if json_response?
  @body = [@body.to_json]
  @headers["Content-Length"] = @body[0].size.to_s
end
...