class Grape::Middleware::Formatter

Public Instance Methods

after() click to toggle source
# File lib/grape/middleware/formatter.rb, line 26
def after
  status, headers, bodies = *@app_response
  # allow content-type to be explicitly overwritten
  api_format = mime_types[headers["Content-Type"]] || env['api.format']
  formatter = Grape::Formatter::Base.formatter_for api_format, options
  begin
    bodymap = bodies.collect do |body|
      formatter.call body, env
    end
  rescue Grape::Exceptions::InvalidFormatter => e
    throw :error, status: 500, message: e.message
  end
  headers['Content-Type'] = content_type_for(env['api.format']) unless headers['Content-Type']
  Rack::Response.new(bodymap, status, headers).to_a
end
before() click to toggle source
# File lib/grape/middleware/formatter.rb, line 21
def before
  negotiate_content_type
  read_body_input
end
default_options() click to toggle source
# File lib/grape/middleware/formatter.rb, line 6
def default_options
  {
    default_format: :txt,
    formatters: {},
    parsers: {}
  }
end
headers() click to toggle source
# File lib/grape/middleware/formatter.rb, line 14
def headers
  env.dup.inject({}) do |h, (k, v)|
    h[k.to_s.downcase[5..-1]] = v if k.to_s.downcase.start_with?('http_')
    h
  end
end

Private Instance Methods

format_from_extension() click to toggle source
# File lib/grape/middleware/formatter.rb, line 104
def format_from_extension
  parts = request.path.split('.')

  if parts.size > 1
    extension = parts.last
    # avoid symbol memory leak on an unknown format
    return extension.to_sym if content_type_for(extension)
  end
  nil
end
format_from_header() click to toggle source
# File lib/grape/middleware/formatter.rb, line 122
def format_from_header
  mime_array.each do |t|
    return mime_types[t] if mime_types.key?(t)
  end
  nil
end
format_from_params() click to toggle source
# File lib/grape/middleware/formatter.rb, line 115
def format_from_params
  fmt = Rack::Utils.parse_nested_query(env['QUERY_STRING'])["format"]
  # avoid symbol memory leak on an unknown format
  return fmt.to_sym if content_type_for(fmt)
  fmt
end
mime_array() click to toggle source
# File lib/grape/middleware/formatter.rb, line 129
def mime_array
  accept = headers['accept']
  return [] unless accept

  accept_into_mime_and_quality = %r{
    (
      \w+/[\w+.-]+)     # eg application/vnd.example.myformat+xml
    (?:
     (?:;[^,]*?)?       # optionally multiple formats in a row
     ;\s*q=([\d.]+)     # optional "quality" preference (eg q=0.5)
    )?
  }x

  vendor_prefix_pattern = /vnd\.[^+]+\+/

  accept.scan(accept_into_mime_and_quality)
    .sort_by { |_, quality_preference| -quality_preference.to_f }
    .map { |mime, _| mime.sub(vendor_prefix_pattern, '') }
end
negotiate_content_type() click to toggle source
# File lib/grape/middleware/formatter.rb, line 95
def negotiate_content_type
  fmt = format_from_extension || format_from_params || options[:format] || format_from_header || options[:default_format]
  if content_type_for(fmt)
    env['api.format'] = fmt
  else
    throw :error, status: 406, message: "The requested format '#{fmt}' is not supported."
  end
end
read_body_input() click to toggle source

store read input in env

# File lib/grape/middleware/formatter.rb, line 49
def read_body_input
  if (request.post? || request.put? || request.patch? || request.delete?) &&
    (!request.form_data? || !request.media_type) &&
    (!request.parseable_data?) &&
    (request.content_length.to_i > 0 || request.env['HTTP_TRANSFER_ENCODING'] == 'chunked')

    if (input = env['rack.input'])
      input.rewind
      body = env['api.request.input'] = input.read
      begin
        read_rack_input(body) if body && body.length > 0
      ensure
        input.rewind
      end
    end
  end
end
read_rack_input(body) click to toggle source

store parsed input in env

# File lib/grape/middleware/formatter.rb, line 68
def read_rack_input(body)
  fmt = mime_types[request.media_type] if request.media_type
  fmt ||= options[:default_format]
  if content_type_for(fmt)
    parser = Grape::Parser::Base.parser_for fmt, options
    if parser
      begin
        body = (env['api.request.body'] = parser.call(body, env))
        if body.is_a?(Hash)
          if env['rack.request.form_hash']
            env['rack.request.form_hash'] = env['rack.request.form_hash'].merge(body)
          else
            env['rack.request.form_hash'] = body
          end
          env['rack.request.form_input'] = env['rack.input']
        end
      rescue StandardError => e
        throw :error, status: 400, message: e.message
      end
    else
      env['api.request.body'] = body
    end
  else
    throw :error, status: 406, message: "The requested content-type '#{request.media_type}' is not supported."
  end
end
request() click to toggle source
# File lib/grape/middleware/formatter.rb, line 44
def request
  @request ||= Rack::Request.new(env)
end