Crest 1.0.0 Release
Anton Maminov

Anton Maminov @mamantoha

About: Ruby developer, Crystal enthusiast.

Location:
Ukraine
Joined:
Aug 31, 2017

Crest 1.0.0 Release

Publish Date: Oct 14 '21
13 2

This article is about Crest — HTTP and REST client for Crystal programming language.

A little about me

My name is Anton and I'm a self-taught full-stack Ruby on Rails developer.

Back in 2017, I had a desire to learn a new programming language.

Crystal caught my attention because of it's similarity to Ruby and because "Fast as C, Slick as Ruby ©".

Literally you can run the same code in Ruby and in Crystal, and it will work.

Unlike Ruby, Crystal is a typed language, but most of the time it's not required to specify types.

Crystal comes with a great standard library and tools. It has almost all the stuff you need to build applications.
CSV, XML, YAML, JSON, HTTP server/client, and even WebSocket are bundled with Crystal itself, making it super simple to start building something.

Project history

For practical reasons, I decided to re-implement Ruby's rest-client gem to dive into the Crystal.

I started the Crest project at April 2017 when Crystal was 0.21.1.

And in a 7 months I has working implementation with next features:

  • redirects support
  • proxy support
  • support nested hashes for headers, cookies, query params, and form data.
  • multipart file uploads
  • logging

The first stable version 0.9.2 was released on 1 Nov 2017.

After more than 4 years of development and 48 releases, I'm happy to announce version Crest 1.0.0.

Example

The common case of HTTP clients is sending a form data to a server.

Let's implement curl command below:

curl -X POST https://httpbin.org/post\?author\=John+Doe\&offset\=20 -F 'user[name]=Tom' -F 'user[file]=@/path/to/file.png' -H 'Foo: bar' --cookie 'foo=bar' -A 'Mozilla/5.0'
Enter fullscreen mode Exit fullscreen mode

Here is an example showing how to do this in pure Crystal:

require "http/client"

# Builds a multipart/form-data
channel = Channel(String).new(1)
io = IO::Memory.new

HTTP::FormData.build(io) do |formdata|
  channel.send(formdata.content_type)

  formdata.field("user[name]", "Tom")

  File.open("/path/to/file.png") do |file|
    mime = MIME.from_filename(file.path)
    metadata = HTTP::FormData::FileMetadata.new(filename: file.path)
    headers = HTTP::Headers{"Content-Type" => mime}
    formdata.file("user[file]", file, metadata, headers)
  end
end

content_type = channel.receive

# Builds headers
headers = HTTP::Headers{"User-Agent" => "Mozilla/5.0", "Content-Type" => content_type, "Foo" => "bar"}

# Builds cookies
cookies = HTTP::Cookies.new
cookie = HTTP::Cookie.new("foo", "bar")
cookies << cookie

# Adds Cookie headers for the cookies in this collection to the given `HTTP::Headers` instance
cookies.add_request_headers(headers)

# Build a URL encoded HTTP query
params = URI::Params.encode({"author" => "John Doe", "offset" => "20"})

# Make a request
response = HTTP::Client.post(
  URI.new("https", "httpbin.org", path: "/post", query: params),
  headers: headers,
  body: io.to_s
)

puts response.body
Enter fullscreen mode Exit fullscreen mode

Here is an example showing how to do the same with Crest:

require "crest"

response = Crest.post(
  "https://httpbin.org/post",
  form: {"user" => {"name" => "Tom", "file" => File.open("/path/to/file.png")}},
  params: {"author" => "John Doe", "offset" => "20"},
  headers: {"Foo" => "bar"},
  cookies: {"foo" => "bar"},
  user_agent: "Mozilla/5.0"
)

puts response.body
Enter fullscreen mode Exit fullscreen mode

Bonus

Do you remember a curl command from the beginning of this article?
Crest have a .to_curl method to convert Crest::Request object to curl command.

puts response.to_curl
# => curl -X POST https://httpbin.org/post?author=John+Doe&offset=20 -F 'user[name]=Tom' -F 'user[file]=@/home/mama/ruby/crystal/crest/spec/support/fff.png' -H 'Foo: bar' -H 'User-Agent: Mozilla/5.0' -H 'Cookie: foo=bar' -H 'Content-Type: multipart/form-data'
Enter fullscreen mode Exit fullscreen mode

If you have any questions, please let me know. I'd love to get your feedback!

Comments 2 total

Add comment