Aitch

Build Status Code Climate Test Coverage RubyGems

A simple HTTP client.

Features:

  • Supports Gzip|Deflate response
  • Automatically parses JSON, HTML and XML responses
  • Automatically follows redirect

Installation

Add this line to your application's Gemfile:

gem 'aitch'

And then execute:

$ bundle

Or install it yourself as:

$ gem install aitch

Usage

Configuration

These are the default settings:

Aitch.configure do |config|
  # Set request timeout.
  config.timeout = 5

  # Set default headers.
  config.default_headers = {}

  # Set follow redirect.
  config.follow_redirect = true

  # Set redirection limit.
  config.redirect_limit = 5

  # Set the user agent.
  config.user_agent = "Aitch/0.0.1 (http://rubygems.org/gems/aitch)"

  # Set the logger.
  config.logger = nil
end

Requests

Performing requests:

response = Aitch.get("http://example.org", params, headers, options)
           Aitch.post("http://example.org", params, headers, options)
           Aitch.put("http://example.org", params, headers, options)
           Aitch.patch("http://example.org", params, headers, options)
           Aitch.delete("http://example.org", params, headers, options)
           Aitch.options("http://example.org", params, headers, options)
           Aitch.trace("http://example.org", params, headers, options)
           Aitch.head("http://example.org", params, headers, options)

You can also use a DSL.

response = Aitch.get do
  url "http://simplesideias.com.br"
  headers Authorization: "Token token=abc"
  options follow_redirect: false
  params a: 1, b: 2
end

Response

The response object:

response.html?
response.xml?
response.json?
response.content_type
response.headers
response.location
response.success?         # status >= 200 && status <= 399
response.redirect?        # status 3xx
response.error?           # status 4xx or 5xx
response.error            # response error
response.body             # returned body
response.data             # Parsed response body

Parsing JSON, XML and HTML with Nokogiri

If your response is a JSON, XML or a HTML content type, we'll automatically convert the response into the appropriate object.

response = Aitch.get("http://simplesideias.com.br")

response.html.class
#=> Nokogiri::HTML::Document

response.html.css("h1").size
#=> 69

response = Aitch.get("http://simplesideias.com.br/feed")

response.xml.class
#=> Nokogiri::XML::Document

response.xml.css("item").size
#=> 10

response = Aitch.get("https://api.github.com/users/fnando")
response.json.class
#=> Hash

response.json["login"]
#=> fnando

Following redirects

The configuration:

Aitch.configure do |config|
  config.follow_redirect = true
  config.redirect_limit = 10
end

The request:

Aitch.get("http://example.org")

If the redirect limit is exceeded, then the Aitch::TooManyRedirectsError exception is raised.

Basic auth

Setting basic auth credentials:

response = Aitch.get do
  url "http://restrict.example.org/"
  options user: "john", password: "test"
end

Setting custom headers

Aitch.get do
  url "http://example.org"
  headers "User-Agent" => "MyBot/1.0.0"
end

The header value can be a callable object.

Aitch.configure do |config|
  config.default_headers = {
    "Authorization" => -> { "Token token=#{ENV.fetch("API_TOKEN")}" }
  }
end

Creating namespaced requests

Sometimes you don't want to use the global settings (maybe you're building a lib). In this case, you can instantiate the namespace.

Request = Aitch::Namespace.new
Request.configure do |config|
  config.user_agent = "MyLib/1.0.0"
end

Request.get("http://example.org")

Validating responses

When you know the kind of response you're expecting, you can validate it by specifying the expect option.

Aitch.get do
  url "http://example.org"
  options expect: 200
end

If this request receives anything other than 200, it will raise a Aitch::StatusCodeError exception.

Expect(200 OK) <=> Actual(404 Not Found)

You can also provide a list of accepted statuses, like expect: [200, 201].

Response Parsers

You can register new response parsers by using Aitch::ResponseParser.register(name, parser), where parser must implement the methods match?(content_type) and load(response_body). This is how you could load CSV values.

require "csv"

module CSVParser
  def self.type
    :csv
  end

  def self.match?(content_type)
    content_type.to_s =~ /csv/
  end

  def self.load(source)
    CSV.parse(source.to_s)
  end
end

Aitch::ResponseParser.prepend(:csv, CSVParser)

The default behavior is returning the response body. You can replace it as the following:

module DefaultParser
  def self.type
    :default
  end

  def self.match?(content_type)
    true
  end

  def self.load(source)
    source.to_s
  end
end

# You should use append here, to ensure
# that is that last parser on the list.
Aitch::ResponseParser.append(:default, DefaultParser)

Aitch comes with response parsers for HTML, XML and JSON.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request