Simple HTTP and REST client for Crystal, inspired by the Ruby's RestClient gem.
Crystal Makefile
Clone or download
Latest commit 1454818 Jul 19, 2018
Failed to load latest commit information.
docs add docs/ to gitignore May 18, 2018
logo logo (#92) Jul 5, 2018
playground update changelog and playground Jul 16, 2018
samples Crystal 0.25 (#87) Jun 15, 2018
spec change specs Jul 19, 2018
src fix require Jul 17, 2018
.gitignore add docs/ to gitignore May 18, 2018
.travis.yml fix flatten_params May 14, 2018 v0.12.0 Jul 17, 2018
LICENSE 0.9.6 Jan 5, 2018
Makefile use ps aux to kill server instead of cat Feb 18, 2018 update readme Jul 19, 2018
shard.yml v0.12.0 Jul 17, 2018


Build Status GitHub release Commits Since Last Release Docs License

Simple HTTP and REST client for Crystal, inspired by the Ruby's RestClient gem.


Add this to your application's shard.yml:

    github: mamantoha/crest


require "crest"

Basic usage:

  params: {:lang => "en"}
# curl -L ""
  form: {:age => 27, :name => {:first => "Kurt", :last => "Cobain"}}
# curl -L --data "age=27&name[first]=Kurt&name[last]=Cobain" -X POST ""

Passing advanced options

Crest::Request accept next parameters:

Mandatory parameters:

  • :method - HTTP method (:get. :post, :put, :patch, :delete, :options)
  • :url - URL (e.g.:

Optional parameters:

  • :headers - a hash containing the request headers
  • :cookies - a hash containing the request cookies
  • :form - a hash containing form params
  • :params - a hash that represent query-string separated from the preceding part by a question mark (?) a sequence of attribute–value pairs separated by a delimiter (&)
  • :user and :password - for Basic Authentication
  • :p_addr, :p_port, :p_user, and :p_pass - specify a per-request proxy by passing these parameters
  • :max_redirects - maximum number of redirections (default to 10)
  • :logging - enable logging (default to false)
  • :logger - set logger (default to Crest::CommonLogger)
  • :handle_errors - error handling (default to true)
  • :http_client - instance of HTTP::Client

More detailed examples:

request =,
  headers: {"Content-Type" => "application/json"},
  form: {:width => 640, "height" => "480"}
# curl -L --data "width=640&height=480" --header "Content-Type: application/json" -X POST ""

  params: {:width => 640, "height" => "480"},
  headers: {"Content-Type" => "application/json"})
# curl -L --header "Content-Type: application/json" ""

  p_addr: "",
  p_port: 3128,
  p_user: "admin",
  p_pass: "1234"
# curl -L --proxy --proxy-user admin:1234 ""

A block can be passed to the Crest::Request instance.

This block will then be called with the Crest::Request.

request =, "") do |request|
  request.headers.add("foo", "bar")

# curl -L --header "foo: bar"

Access HTTP::Client

You can access HTTP::Client via the http_client instance method.

This is usually used to set additional options (e.g. read timeout, authorization header etc.)

client ="")
client.read_timeout = 1.second

    http_client: client
rescue IO::Timeout
  puts "Timeout!"


Yeah, that's right! This does multipart sends for you!

file ="#{__DIR__}/example.png")"", form: {:image => file})
file ="#{__DIR__}/example.png")
resource ="")
response = resource["/post"].post(form: {:image => file})

JSON payload

crest does not speak JSON natively, so serialize your form to a string before passing it to crest.
  headers: {"Content-Type" => "application/json"},
  form: {:foo => "bar"}.to_json


Request headers can be set by passing a hash containing keys and values representing header names and values:

response = Crest.get(
  headers: {"Authorization" => "Bearer cT0febFoD5lxAlNAXHo6g"}
# => {"Authorization" => ["Bearer cT0febFoD5lxAlNAXHo6g"]}


Request and Response objects know about HTTP cookies, and will automatically extract and set headers for them as needed:

response = Crest.get(
  params: {"k1" => "v1", "k2" => "v2"}
# => {"k1" => "v1", "k2" => "v2"}

response = Crest.get(
  cookies: {"k1" => "v1"}
# => {"k1" => "v1"}

Basic authentication

For basic access authentication for an HTTP user agent you should to provide a user name and password when making a request.

  user: "user",
  password: "passwd"
# curl -L --user user:passwd


If you need to use a proxy, you can configure individual requests with the proxy host and port arguments to any request method:

  p_addr: "localhost",
  p_port: 3128

To use HTTP Basic Auth with your proxy, use next syntax:

  p_addr: "localhost",
  p_port: 3128,
  p_user: "user",
  p_pass: "qwerty"


Logger class is completely taken from halite shard. Thanks icyleaf!

By default, the Crest does not enable logging. You can enable it per request by setting logging: true:

Crest.get("", logging: true)

Filter sensitive information from logs with a regex matcher

resource = Crest::Request.get("", params: {api_key => "secret"}, logging: true) do |request|
  request.logger.filter(/(api_key=)(\w+)/, "\\1[REMOVED]")

# => crest | 2018-07-04 14:49:49 | GET |[REMOVED]

Customize logging

You can create the custom logger by integration Crest::Logger abstract class. Here has two methods must be implement: Crest::Logger.request and Crest::Logger.response.

class MyLogger < Crest::Logger
  def request(request) ">> | %s | %s" % [request.method, request.url]

  def response(response) "<< | %s | %s" % [response.status_code, response.url]

Crest.get("", logging: true, logger:


A Crest::Resource class can be instantiated for access to a RESTful resource, including authentication, proxy and logging.

Additionally, you can set default params and headers separately. So can use Crest::Resource to share common headers and params.

The final headers and params consist of:

  • default headers from initializer
  • headers provided in call method (get, post, etc)

This is especially useful if you wish to define your site in one place and call it in multiple locations.

resource =
  params: {"key" => "value"},
  headers: {"Content-Type" => "application/json"}

  headers: {"Auth-Token" => "secret"}

  form: {:height => 100, "width" => "100"},
  params: {:secret => "secret"}

Use the [] syntax to allocate subresources:

site ="")

site["/post"].post({:param1 => "value1", :param2 => "value2"})
# curl -L --data "param1=value1&param2=value2" -X POST

You can pass suburl through Request#http_verb methods:

site ="")"/post", form: {:param1 => "value1", :param2 => "value2"})
# curl -L --data "param1=value1&param2=value2" -X POST

site.get("/get", params: {:status => "active"})
# curl -L

A block can be passed to the Crest::Resource instance.

This block will then be called with the Crest::Resource.

resource ="") do |resource|
  resource.headers.merge!({"foo" => "bar"})


With HTTP basic authentication:

resource =
  user: "user",
  password: "passwd"

With Proxy authentication:

resource =
  p_host: "localhost",
  p_port: 3128


  • for result codes between 200 and 207, a Crest::Response will be returned
  • for result codes 301, 302, 303 or 307, the redirection will be followed and the request transformed into a GET
  • for other cases, a Crest::RequestFailed holding the Response will be raised
  • call .response on the exception to get the server's response
# => HTTP status code 404: Not Found (Crest::NotFound)

rescue ex : Crest::NotFound
  puts ex.response

To not raise exceptions but return the Crest::Response you can set :handle_errors => false.

response = Crest.get("", handle_errors: false)
response.status_code # => 404


By default, crest will follow HTTP 30x redirection requests.

To disable automatic redirection, set :max_redirects => 0.

Crest::Request.execute(method: :get, url: "", max_redirects: 0)
# => Crest::Found: 302 Found

Result handling

The result of a Crest::Request is a Crest::Response object.

Response objects have several useful methods.

  • Response#body: The response body as a string
  • Response#status_code: The HTTP response code
  • Response#headers: A hash of HTTP response headers
  • Response#cookies: A hash of HTTP cookies set by the server
  • Response#request: The Crest::Request object used to make the request
  • Response#http_client_res: The HTTP::Client::Response object
  • Response#history: A list of each response received in a redirection chain


Install dependencies:


To run test:

make test


crystal play
open http://localhost:8080

Then select the Workbook -> Requests from the menu.


  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 a new Pull Request



Copyright: 2017-2018 Anton Maminov (

This library is distributed under the MIT license. Please see the LICENSE file.