class Blix::Rest::Server

Public Class Methods

new(opts = {}) click to toggle source
# File lib/blix/rest/server.rb, line 6
def initialize(opts = {})
  @_parsers = {}
  @_mime_types = {}

  # register the default parsers and any passed in as options.

  register_parser('html', HtmlFormatParser.new)
  register_parser('json', JsonFormatParser.new)
  register_parser('xml', XmlFormatParser.new)
  register_parser('raw', RawFormatParser.new)
  extract_parsers_from_options(opts)
  @_options = opts
end

Public Instance Methods

_cache() click to toggle source
# File lib/blix/rest/server.rb, line 20
def _cache
  @_cache ||= {}
end
call(env) click to toggle source
# File lib/blix/rest/server.rb, line 141
def call(env)
  req = Rack::Request.new(env)

  verb            = env['REQUEST_METHOD']
  path            = req.path

  blk, path_params, options = RequestMapper.match(verb, path)

  blk, path_params, options = RequestMapper.match('ALL', path) unless blk

  default_format = options && options[:default] && options[:default].to_sym
  force_format = options && options[:force] && options[:force].to_sym
  do_cache = options && options[:cache]
  clear_cache = options && options[:cache_reset]

  query_format = options && options[:query] && req.GET['format'] && req.GET['format'].to_sym

  format = query_format || path_params[:format] || get_format_new(env, options) || default_format || :json

  parser = get_parser(force_format || format)

  return [406, {}, ["Invalid Format: #{format}"]] unless parser

  parser._options = options

  # check for cached response end return with cached response if found.
  #
  if do_cache && _cache["#{verb}|#{format}|#{path}"]
    response = _cache["#{verb}|#{format}|#{path}"]
    return [response.status, response.headers.merge('X-Blix-Cache' => 'cached'), [response.content]]
  end

  response = Response.new

  if parser.__custom_headers
    response.headers.merge! parser.__custom_headers
  else
    parser.set_default_headers(response.headers)
  end

  if blk

    begin
      params = env['params']
      value  = blk.call(path_params, params, req, format, response, @_options)
    rescue ServiceError => e
      response.set(e.status, parser.format_error(e.message), e.headers)
    rescue AuthorizationError => e
      response.set(401, parser.format_error(e.message), AUTH_HEADER => "#{e.type} realm=\"#{e.realm}\", charset=\"UTF-8\"")
    rescue Exception => e
      response.set(500, parser.format_error('internal error'))
      ::Blix::Rest.logger <<  "----------------------------\n#{$!}\n----------------------------"
      ::Blix::Rest.logger <<  "----------------------------\n#{$@}\n----------------------------"
    else # no error
      parser.format_response(value, response)
      # cache response if requested
      _cache.clear if clear_cache
      _cache["#{verb}|#{format}|#{path}"] = response if do_cache
    end

  else
    response.set(404, parser.format_error('Invalid Url'))
  end
  [response.status, response.headers, [response.content]]
end
extract_parsers_from_options(opts) click to toggle source
# File lib/blix/rest/server.rb, line 24
def extract_parsers_from_options(opts)
  opts.each do |k, v|
    next unless k =~ /^(\w*)_parser&/

    format = Regexp.last_match(1)
    parser = v
    register_parser(format, parser)
  end
end
format_error(_message, _format) click to toggle source

convert the response to the appropriate format

# File lib/blix/rest/server.rb, line 137
def format_error(_message, _format)
  parser
end
get_format(env) click to toggle source

accept header can have multiple entries. match on regexp can look like this text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 !!!!!

# File lib/blix/rest/server.rb, line 99
def get_format(env)
  case env['HTTP_ACCEPT']
  when JSON_ENCODED then :json
  when HTML_ENCODED then :html
  when XML_ENCODED then :xml
  end
end
get_format_from_mime(mime) click to toggle source
# File lib/blix/rest/server.rb, line 107
def get_format_from_mime(mime)
  case mime
  when 'application/json' then :json
  when 'text/html' then :html
  when 'application/xml'  then :xml
  when 'application/xhtml+xml' then :xhtml
  when '*/*' then :*
  end
end
get_format_new(env, options) click to toggle source

attempt to handle mjltiple accept formats here.. mime can include '…/*' and '/' FIXME

# File lib/blix/rest/server.rb, line 120
def get_format_new(env, options)
  accept = options && options[:accept] || :json
  accept = [accept].flatten

  requested = env['HTTP_ACCEPT'].to_s.split(',')
  requested.each do |request|
    parts = request.split(';') # the quality part is after a ;
    mime = parts[0].strip # the mime type
    try = get_format_from_mime(mime)
    next unless try
    return accept[0] || :json if try == :*
    return try if accept.include?(try)
  end
  nil # no match found
end
get_parser(format) click to toggle source
# File lib/blix/rest/server.rb, line 41
def get_parser(format)
  @_parsers[format.to_s]
end
get_parser_from_type(type) click to toggle source
# File lib/blix/rest/server.rb, line 45
def get_parser_from_type(type)
  @_mime_types[type.downcase]
end
register_parser(format, parser) click to toggle source
# File lib/blix/rest/server.rb, line 49
def register_parser(format, parser)
  raise "#{k} must be an object with parent class Blix::Rest::FormatParser" unless parser.is_a?(FormatParser)

  parser._format = format
  @_parsers[format.to_s.downcase] = parser
  parser._types.each { |t| @_mime_types[t.downcase] = parser } # register each of the mime types
end
retrieve_params(env) click to toggle source
# File lib/blix/rest/server.rb, line 57
def retrieve_params(env)
  post_params = {}
  body        = ''
  params = env['params'] || {}
  params.merge!(::Rack::Utils.parse_nested_query(env['QUERY_STRING']))

  if env['rack.input']
    post_params = ::Rack::Utils::Multipart.parse_multipart(env)
    unless post_params
      body = env['rack.input'].read
      env['rack.input'].rewind

      if body.empty?
        post_params = {}
      else
        begin
          post_params = case (env['CONTENT_TYPE'])
                        when URL_ENCODED
                          ::Rack::Utils.parse_nested_query(body)
                        when JSON_ENCODED then
                          json = MultiJson.load(body)
                          if json.is_a?(Hash)
                            json
                          else
                            { '_json' => json }
                          end
                        else
                          {}
          end
        rescue StandardError => e
          raise BadRequestError, "Invalid parameters: #{e.class}"
        end
      end
    end
  end
  [params, post_params, body]
end
set_custom_headers(format, headers) click to toggle source
# File lib/blix/rest/server.rb, line 34
def set_custom_headers(format, headers)
  parser = get_parser(format)
  raise "parser not found for custom headers format=>#{format}" unless parser

  parser.__custom_headers = headers
end