lib/stockboy/providers/http.rb
require 'stockboy/provider'
require 'httpi'
module Stockboy::Providers
# Fetches data from an HTTP endpoint
#
# == Job template DSL
#
# provider :http do
# get "http://example.com/api/things"
# end
#
class HTTP < Stockboy::Provider
# @!group Options
# Shorthand for +:method+ and +:uri+ using HTTP GET
#
# @!attribute [rw] get
# @return [String]
# @example
# get 'http://example.com/api/things'
#
dsl_attr :get, attr_writer: false
# Shorthand for +:method+ and +:uri+ using HTTP POST
#
# @!attribute [rw] post
# @return [String]
# @example
# post 'http://example.com/api/search'
#
dsl_attr :post, attr_writer: false
# HTTP method: +:get+ or +:post+
#
# @!attribute [rw] method
# @return [Symbol]
# @example
# method :post
#
dsl_attr :method, attr_writer: false
# HTTP request headers
#
# @!attribute [rw] headers
# @return [String]
# @example
# headers content_type: "text/json"
#
dsl_attr :headers
# HTTP request body
#
# @!attribute [rw] body
# @return [String]
# @example
# body "<getData></getData>"
#
dsl_attr :body
# User name for basic auth connection credentials
#
# @!attribute [rw] username
# @return [String]
# @example
# username "arthur"
#
dsl_attr :username
# Password for basic auth connection credentials
#
# @!attribute [rw] password
# @return [String]
# @example
# password "424242"
#
dsl_attr :password
def uri
return nil if @uri.nil? || @uri.to_s.empty?
URI(@uri).tap { |u| u.query = URI.encode_www_form(@query) if @query }
end
def uri=(uri)
@uri = uri
end
# HTTP host and path to the data resource
#
# @!attribute [rw] uri
# @return [String]
# @example
# uri 'http://example.com/api/things'
#
dsl_attr :uri, attr_accessor: false, alias: :url
# Hash of query options
#
# @!attribute [rw] query
# @return [Hash]
# @example
# query start: 1, limit: 100
#
dsl_attr :query
def method=(http_method)
return @method = nil unless %w(get post).include? http_method.to_s.downcase
@method = http_method.to_s.downcase.to_sym
end
def get=(uri)
@method = :get
@uri = uri
end
def post=(uri)
@method = :post
@uri = uri
end
# @!endgroup
# Initialize an HTTP provider
#
def initialize(opts={}, &block)
super(opts, &block)
self.uri = opts[:uri]
self.method = opts[:method] || :get
self.query = opts[:query] || Hash.new
self.headers = opts[:headers] || Hash.new
self.body = opts[:body]
self.username = opts[:username]
self.password = opts[:password]
DSL.new(self).instance_eval(&block) if block_given?
end
def client
orig_logger, HTTPI.logger = HTTPI.logger, logger
req = HTTPI::Request.new.tap { |c| c.url = uri }
req.auth.basic(username, password) if username && password
req.headers = headers
req.body = body
block_given? ? yield(req) : req
ensure
HTTPI.logger = orig_logger
end
private
def validate
errors << "uri must be specified" unless uri
errors << "method (:get, :post) must be specified" unless method
errors << "body must be specified" if [:post, :put, :patch].include?(method) && body.to_s.empty?
errors.empty?
end
def fetch_data
client do |request|
response = HTTPI.request(method, request)
if response.error?
errors << "HTTP response error: #{response.code}"
else
@data = response.body
end
end
end
end
end