Simple flexible HTTP client middleware
0.1.2 released

Cossack crystal Cossack logo

Build Status

Simple and flexible HTTP client for Crystal with middleware and test support.


Add this to your application's shard.yml:

    github: greyblake/crystal-cossack
    version: ~> 0.1

And install dependencies:

crystal deps


require "cossack"

# Send a single GET request
response = Cossack.get("")
response.body  # => "Bla bla bla"

# Create an instance of a client with basic URL
cossack ="") do |client|
  # Set headers
  client.headers["Authorization"] = "Bearer SECRET-TOKEN"

  # Modify request options (by default connect_timeout is 30 sec)
  client.request_options.connect_timeout = 60.seconds

# Send GET request to
response = cossack.get("/info") do |request|
  # modify a particular request
  request.headers["Accept-Language"] = "eo"

# Explore response
response.status                     # => 200
response.body                       # => "Info"
response.headers["Content-Length"]  # => 4

# Send POST request"/comments", "Request body")

The concept

Cossack is inspired by Faraday and Hurley libraries from the ruby world.

The main things are: Client, Request, Response, Connection, Middleware.

  • Client - provides a convenient API to build and perform HTTP requests. Keeps default request parameters(base url, headers, request options, etc.)
  • Request - HTTP request(method, uri, headers, body) with its options (e.g. connect_timeout`).
  • Response - HTTP response(method, headers, body).
  • Connection - executes actual Request, used by Client and can be subsituted (e.g. for test purposes).
  • Middleware - can be injected between Client and Connection to execute some custom stuff(e.g. logging, caching, etc.)

The following time diagram shows how it works:

Crystal HTTP client Cossack time diagram

Using Middleware

Middleware are custom classes that are injected in between Client and Connection. They allow you to intercept request or response and modify them.

Middleware class should be inherited from Cossack::Middleware and implement #call(Cossack::Request) : Cossack::Response interface. It also should execute in order to forward a request.

Let's implement simple middleware that prints all requests:

class StdoutLogMiddleware < Cossack::Middleware
  def call(request)
    puts "#{request.method} #{request.uri}"
    response =
    puts "Response: #{response.status} #{response.body}"

Now let's apply it to a client:

cossack ="") do |client|
  client.use StdoutLogMiddleware

# Every request will be logged to STDOUT
response = cossack.get("/test")

Cossack has some preimplemented middleware, don't be afraid to take a look.

Connection Swapping

Connection is something, that receives Request and returns back Response. By default client as HTTPConnection, that performs real HTTP requests. But if you don't like it by some reason, or you want to modify its behaviour, you can replace it with you own. It must be a proc a subclass of Cossack::Connection:

client =
client.connection = -> (request : Cossack::Request) do, "Everything is fine")

response = client.put("")
puts response.body # => "Everything is fine"


There is more use of connection swapping, when it comes to testing. Cossack has TestConnection that allows you to stub HTTP requests in specs.

describe "TestConnection example" do
  it "stubs real requests" do
    connection =
    connection.stub_get("/hello/world", {200, "Hello developer!"})

    client ="")
    client.connection = connection

    response = client.get("/hello/world")
    response.status.should eq 200
    response.body.should eq "Hello developer!"

You can find real examples in Glosbe and GoogleTranslate clients. Or in Cossack specs itself.


How to follow redirections

If you want a client to follow redirections, you can use Cossack::RedirectionMiddleware:

cossack = do |client|
  # follow up to 10 redirections (by default 5)
  client.use Cossack::RedirectionMiddleware, limit: 10



To run all tests:

make test

To run unit tests:

make test_unit

To run acceptance tests:

make test_acceptance


  • [ ] Implement before / after callbacks
  • [ ] Add context/env Hash(String, String) to Request and Response
  • [ ] Find a way to perform basic autentication


If you like the concept and design of the library, then may be we can bring the idea to Crystal! There is no need to keep this library, if we can have the same things in standard library. And I guess crystal maintainers won't resist. But first we need to get positive feedback to ensure we're moving in the right direction =)


  • greyblake Sergey Potapov - creator, maintainer
  github: crystal-community/cossack
  version: ~> 0.1.2
License LGPLv3
Crystal none


Dependencies 0

Development Dependencies 2

  • kemal
    {'github' => 'sdogruyol/kemal'}
  • spec2 crystal-0-18-0
    {'branch' => 'crystal-0-18-0', 'github' => 'greyblake/'}

Dependents 1

Last synced .
search fire star recently