module Swagger
class Request
require 'uri'
require 'addressable/uri'
require 'typhoeus'
require "swagger/version"
attr_accessor :host, :path, :format, :params, :body, :http_method, :headers, :form_params
# All requests must have an HTTP method and a path
# Optionals parameters are :params, :headers, :body, :format, :host
#
def initialize(http_method, path, attributes={})
attributes[:format] ||= Swagger.configuration.format
attributes[:params] ||= {}
# Set default headers
default_headers = {
'Content-Type' => "application/#{attributes[:format].downcase}",
:api_key => Swagger.configuration.api_key,
'User-Agent' => Swagger.configuration.user_agent
}
# api_key from headers hash trumps the default, even if its value is blank
if attributes[:headers].present? && attributes[:headers].has_key?(:api_key)
default_headers.delete(:api_key)
end
# api_key from params hash trumps all others (headers and default_headers)
if attributes[:params].present? && attributes[:params].has_key?(:api_key)
default_headers.delete(:api_key)
attributes[:headers].delete(:api_key) if attributes[:headers].present?
end
# Merge argument headers into defaults
attributes[:headers] = default_headers.merge(attributes[:headers] || {})
# Stick in the auth token if there is one
if Swagger.authenticated?
attributes[:headers].merge!({:auth_token => Swagger.configuration.auth_token})
end
self.http_method = http_method.to_sym
self.path = path
attributes.each do |name, value|
send("#{name.to_s.underscore.to_sym}=", value)
end
end
# Construct a base URL
#
def url(options = {})
u = Addressable::URI.new(
:scheme => Swagger.configuration.scheme,
:host => Swagger.configuration.host,
:path => self.interpreted_path,
:query => self.query_string.sub(/\?/, '')
).to_s
# Drop trailing question mark, if present
u.sub! /\?$/, ''
# Obfuscate API key?
u.sub! /api\_key=\w+/, 'api_key=YOUR_API_KEY' if options[:obfuscated]
u
end
# Iterate over the params hash, injecting any path values into the path string
#
# e.g. /word.{format}/{word}/entries => /word.json/cat/entries
def interpreted_path
p = self.path.dup
# Stick a .{format} placeholder into the path if there isn't
# one already or an actual format like json or xml
# e.g. /words/blah => /words.{format}/blah
if Swagger.configuration.inject_format
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
p = p.sub(/^(\/?\w+)/, "\\1.#{format}")
end
end
# Stick a .{format} placeholder on the end of the path if there isn't
# one already or an actual format like json or xml
# e.g. /words/blah => /words/blah.{format}
if Swagger.configuration.force_ending_format
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
p = "#{p}.#{format}"
end
end
p = p.sub("{format}", self.format.to_s)
URI.encode [Swagger.configuration.base_path, p].join("/").gsub(/\/+/, '/')
end
# Massage the request body into a state of readiness
# If body is a hash, camelize all keys then convert to a json string
#
def body=(value)
if value.is_a?(Hash)
value = value.inject({}) do |memo, (k,v)|
memo[k.to_s.camelize(:lower).to_sym] = v
memo
end
end
@body = value
end
# If body is an object, JSONify it before making the actual request.
# For form parameters, remove empty value
def outgoing_body
# http form
if @body.nil? && @form_params && !@form_params.empty?
data = form_params.dup
data.each do |key, value|
data[key] = value.to_s if value && !value.is_a?(File) # remove emtpy form parameter
end
data
else # http body is JSON
@body.is_a?(String) ? @body : @body.to_json
end
end
# Construct a query string from the query-string-type params
def query_string
# Iterate over all params,
# .. removing the ones that are part of the path itself.
# .. stringifying values so Addressable doesn't blow up.
query_values = {}
self.params.each_pair do |key, value|
next if self.path.include? "{#{key}}" # skip path params
next if value.blank? && value.class != FalseClass # skip empties
if Swagger.configuration.camelize_params
key = key.to_s.camelize(:lower).to_sym unless key.to_sym == :api_key # api_key is not a camelCased param
end
query_values[key] = value.to_s
end
# We don't want to end up with '?' as our query string
# if there aren't really any params
return "" if query_values.blank?
# Addressable requires query_values to be set after initialization..
qs = Addressable::URI.new
qs.query_values = query_values
qs.to_s
end
def make
#TODO use configuration setting to determine if debugging
#logger = Logger.new STDOUT
#logger.debug self.url
response = case self.http_method.to_sym
when :get,:GET
Typhoeus::Request.get(
self.url,
:headers => self.headers.stringify_keys,
)
when :post,:POST
Typhoeus::Request.post(
self.url,
:body => self.outgoing_body,
:headers => self.headers.stringify_keys,
)
when :patch,:PATCH
Typhoeus::Request.patch(
self.url,
:body => self.outgoing_body,
:headers => self.headers.stringify_keys,
)
when :put,:PUT
Typhoeus::Request.put(
self.url,
:body => self.outgoing_body,
:headers => self.headers.stringify_keys,
)
when :delete,:DELETE
Typhoeus::Request.delete(
self.url,
:body => self.outgoing_body,
:headers => self.headers.stringify_keys,
)
end
Response.new(response)
end
def response
self.make
end
def response_code_pretty
return unless @response.present?
@response.code.to_s
end
def response_headers_pretty
return unless @response.present?
# JSON.pretty_generate(@response.headers).gsub(/\n/, '
') # <- This was for RestClient
@response.headers.gsub(/\n/, '
') # <- This is for Typhoeus
end
end
end