onyx-http

REST API framework with type-safe params and separate business and rendering layers, based on onyx-http web framework router websockets modular http-handler onyxframework
0.5.0-alpha.1 released
onyxframework/http
142 11 7
Onyx Framework

⚛️ Atom::Web

Built with Crystal Build status Docs Releases Awesome vladfaust.com Patrons count

A collection of HTTP components used in Atom Framework.

Become Patron

Installation

Add this to your application's shard.yml:

dependencies:
  atom-web:
    github: atomframework/web
    version: ~> 0.5.0

This shard follows Semantic Versioning v2.0.0, so check releases and change the version accordingly.

Included components

Usage

Without Atom

Atom reduces overall code by wrapping common scenarios into macros, so the code below is quite verbose.

Basic example

require "atom-web"

struct KnockKnock
  include Atom::Action

  params do
    type who : String
    type how_many : Int32
  end

  def call
    how_many.times do
      text("Knock-knock #{who}\n")
    end
  end
end

logger = Logger.new(STDOUT, Logger::DEBUG)
request_logger = Atom::Handlers::RequestLogger.new(logger)

router = Atom::Handlers::Router.new do
  get "/:who", KnockKnock
end

server = HTTP::Server.new([request_logger, router]) do |context|
  if proc = context.proc
    proc.call(context)
  else
    context.response.respond_with_error("Not Found: #{context.request.path}", 404)
  end
rescue ex : Params::Error
  context.response.respond_with_error(ex.message, 400)
end

server.bind_tcp(5000)
logger.info("Listening at http://#{server.addresses.first}")

server.listen

# DEBUG -- :     GET /me 200 177μs
curl -X GET -d "howMany=2" http://127.0.0.1:5000/me
Knock-knock me
Knock-knock me

Custom JSON renderer example

In this example, an application always returns formatted JSON responses.

require "atom-web"

record User, id : Int32, name : String

Users = {1 => User.new(1, "John")}

module CustomRenderer
  def render(value)
    success = (200..299) === context.response.status_code

    json = JSON::Builder.new(context.response.output)
    json.document do
      json.object do
        json.field("success", success)
        json.field(success ? "data" : "error") do
          value.to_json(json)
        end
        json.field("status", context.response.status_code)
      end
    end

    context.response.content_type = "application/json; charset=utf-8"
  end
end

struct Actions::GetUser
  include Atom::Action
  include CustomRenderer

  params do
    type id : Int32
  end

  def call
    if user = Users[id]?
      render(Views::User.new(user))
    else
      halt(404, "User not found with id #{id}")
    end
  end
end

struct Views::User
  def initialize(@user : ::User)
  end

  def to_json(json)
    json.object do
      json.field("id", @user.id)
      json.field("name", @user.name)
    end
  end
end

request_logger = Atom::Handlers::RequestLogger.new(Logger.new(STDOUT, Logger::DEBUG))

router = Atom::Handlers::Router.new do
  get "/users/:id", Actions::GetUser
end

server = HTTP::Server.new([request_logger, router]) do |context|
  if proc = context.proc
    proc.call(context)
  else
    context.response.respond_with_error("Not Found: #{context.request.path}", 404)
  end
rescue ex : Params::Error
  context.response.respond_with_error(ex.message, 400)
end

server.bind_tcp(5000)
puts "Listening at http://#{server.addresses.first}"
server.listen

Websockets example

We call them Channels for convenience.

require "atom-web"

class Notifications
  include Atom::Channel

  @@subscriptions = Array(self).new

  def self.notify(message)
    @@subscriptions.each &.socket.send(message)
  end

  def on_open
    socket.send("Hello")
    @@subscriptions.push(self)
  end

  def on_close
    @@subscriptions.delete(self)
  end
end

router = Atom::Handlers::Router.new do
  ws "/notifications" do |socket, env|
    Notifications.subscribe(socket, env)
  end
end

# Later in the code...

Notifications.notify("Something happened!") # Will notify all subscribers binded to this particular Crystal process

Contributing

  1. Fork it ( https://github.com/atomframework/web/fork )
  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

Contributors

onyx-http:
  github: onyxframework/http
  version: ~> 0.5.0-alpha.1
License MIT
Crystal 0.27.0

Authors

Dependencies 4

  • callbacks ~> 0.1.1
    {'github' => 'vladfaust/callbacks.cr', 'version' => '~> 0.1.1'}
  • http-params-serializable~vladfaust ~> 0.1.0
    {'github' => 'vladfaust/params.cr', 'version' => '~> 0.1.0'}
  • radix ~> 0.3.8
    {'github' => 'luislavena/radix', 'version' => '~> 0.3.8'}
  • time_format ~> 0.1.0
    {'github' => 'vladfaust/time_format.cr', 'version' => '~> 0.1.0'}

Development Dependencies 0

Dependents 2

Last synced .
search fire star recently