Crest 1.0.0 Release
Tags: crystal
Published: 2021-10-14 11:29:46

---
title: Crest 1.0.0 Release
published: true
description: 
tags: crystal
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k39oq9yvjl5suy6iipng.jpg
---

This article is about [Crest](https://github.com/mamantoha/crest) — HTTP and REST client for [Crystal](https://crystal-lang.org/) 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](https://github.com/rest-client/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](https://github.com/mamantoha/crest/releases/tag/v1.0.0).


## Example

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

Let's implement curl command below:

```console
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'
```

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

```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
```

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

```crystal
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
```

## 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.

```crystal
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'
```

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