module Her # This class is where all HTTP requests are made. Before using Her, you must configure it # so it knows where to make those requests. In Rails, this is usually done in `config/initializers/her.rb`: class API # @private attr_reader :connection, :options # Constants FARADAY_OPTIONS = [:request, :proxy, :ssl, :builder, :url, :parallel_manager, :params, :headers, :builder_class].freeze # Setup a default API connection. Accepted arguments and options are the same as {API#setup}. def self.setup(opts = {}, &block) @default_api = new(opts, &block) end # Create a new API object. This is useful to create multiple APIs and use them with the `uses_api` method. # If your application uses only one API, you should use Her::API.setup to configure the default API # # @example Setting up a new API # api = Her::API.new :url => "https://api.example" do |connection| # connection.use Faraday::Request::UrlEncoded # connection.use Her::Middleware::DefaultParseJSON # end # # class User # uses_api api # end def initialize(*args, &blk) setup(*args, &blk) end # Setup the API connection. # # @param [Hash] opts the Faraday options # @option opts [String] :url The main HTTP API root (eg. `https://api.example.com`) # @option opts [String] :ssl A hash containing [SSL options](https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates) # # @return Faraday::Connection # # @example Setting up the default API connection # Her::API.setup :url => "https://api.example" # # @example A custom middleware added to the default list # class MyAuthentication < Faraday::Middleware # def call(env) # env[:request_headers]["X-API-Token"] = "bb2b2dd75413d32c1ac421d39e95b978d1819ff611f68fc2fdd5c8b9c7331192" # @app.call(env) # end # end # Her::API.setup :url => "https://api.example.com" do |connection| # connection.use Faraday::Request::UrlEncoded # connection.use Her::Middleware::DefaultParseJSON # connection.use MyAuthentication # connection.use Faraday::Adapter::NetHttp # end # # @example A custom parse middleware # class MyCustomParser < Faraday::Response::Middleware # def on_complete(env) # json = JSON.parse(env[:body], :symbolize_names => true) # errors = json.delete(:errors) || {} # metadata = json.delete(:metadata) || [] # env[:body] = { :data => json, :errors => errors, :metadata => metadata } # end # end # Her::API.setup :url => "https://api.example.com" do |connection| # connection.use Faraday::Request::UrlEncoded # connection.use MyCustomParser # connection.use Faraday::Adapter::NetHttp # end def setup(opts = {}, &blk) opts[:url] = opts.delete(:base_uri) if opts.include?(:base_uri) # Support legacy :base_uri option @options = opts faraday_options = @options.select { |key, _| FARADAY_OPTIONS.include?(key.to_sym) } @connection = Faraday.new(faraday_options) do |connection| yield connection if block_given? end self end # Define a custom parsing procedure. The procedure is passed the response object and is # expected to return a hash with three keys: a main data Hash, an errors Hash # and a metadata Hash. # # @private def request(opts = {}) method = opts.delete(:_method) path = opts.delete(:_path) headers = opts.delete(:_headers) opts.delete_if { |key, _| key.to_s =~ /^_/ } # Remove all internal parameters if method == :options # Faraday doesn't support the OPTIONS verb because of a name collision with an internal options method # so we need to call run_request directly. request.headers.merge!(headers) if headers response = @connection.run_request method, path, opts, headers else response = @connection.send method do |request| request.headers.merge!(headers) if headers if method == :get # For GET requests, treat additional parameters as querystring data request.url path, opts else # For POST, PUT and DELETE requests, treat additional parameters as request body request.url path request.body = opts end end end { :parsed_data => response.env[:body], :response => response } end private # @private def self.default_api(opts = {}) defined?(@default_api) ? @default_api : nil end end end