Hatty CircleCI

A library for creating HTTP services in Crystal

require "hatty"

get "/" do |request, response|
  response.send_text "Hello there!"
end

Hatty.start

Installing

Add this snippet to your shard.yml file

dependencies:
  hatty:
    github: semlette/hatty

Usage

require "hatty"

# Define handlers using `get`, `post`, `put`, `delete` and `patch`

get "/users/:id" do |request, response|
  user = get_user(request.params["id"])
  response.send_json({ data: user })
end

post "/users" do |request, response|
  name = response.body["name"]
  age = response.body["age"]
  new_user = create_user(name, age)
  response.send_json({ success: true, data: new_user })
end

delete "/users/:id" do |request, response|
  token = request.headers["Authorization"]?
  is_admin = is_admin?(token)
  if is_admin
    delete_user(request.params["id"])
    response.send_json({ "success" => true })
  else
    response.send_status 401
  end
end

Hatty.start

Every handler receives a request and a response. The request contains information about the request like the headers, the body, url queries and parameters. The response has properties like the status code, headers and a lot of helper methods for sending stuff back to the client.

Sending stuff

get "/" do |request, response|
  # Note: You can only call `#send...` once
  response.send "<!DOCTYPE><html><body>I have no Content-Type</body></html>"
  response.send_text "I am text/plain"
  response.send_json({ "content-type" => "application/json" })
  response.send_status 404
  response.send_file("../images/logo.png", "our-logo.png")
  response.redirect("/homepage")
end

API documentation for Response

Status codes

Setting the status code

get "/admin" do |request, response|
  response.status_code = 401
  response.send_text "Unauthorized."
end

Using status handlers

Status handlers are handlers that respond to a specific status code. When you call Response#send_status, the request is passed to the status handler with the same status code. If a handler raises an uncaught error, Hatty sends the request to the 500 status handler. It also passes requests with no handler to the 404 status handler.

get "/private" do |request, response|
  response.send_status 404
end

status 404 do |request, response|
  response.send_text "Oops, file not found. ¯\_(ツ)_/¯"
end

Global status handler

Instead of defining a status handler for every status code, you can define a Global Status Handler™. The global status handler will receive all status codes not handled by the status handlers. If you create a status handler for 404 and a global status handler, the global status handler will not receive 404 requests.

status do |code, request, response|
  response.send_text "Oops! Error code #{code}"
end

API documentation for status

API documentation for Response#send_status

Testing

Hatty comes with a testing module which helps you test your routes. Inspired by spec-kemal, requiring hatty/testing imports methods that allows you to test your routes.

Methods

app.cr

require "hatty"

get "/api" do |request, response|
  response.send_json({ "data" => "insert data here" })
end

Hatty.start

app_spec.cr

require "./app"
require "hatty/testing"

describe "GET /api" do
  it "returns json" do
    #         `get` along with other methods are provided by `hatty/testing`
    response = get "/api"

    response.status_code.should eq 200
    response.json?.should be_true
  end
end