Small and flexible HTTP framework for Crystal, built on radbas/routing.cr.
-
Add the dependency to your
shard.yml:dependencies: radbas-framework: github: radbas/framework.cr
-
Run
shards install
require "radbas-framework"
builder = Radbas::ApplicationBuilder.new
# Radbas::Context is an alias for HTTP::Server::Context
builder.get "/", ->(context : Radbas::Context) {
context.response.print "Hello World"
}
app = builder.build
Radbas::ApplicationServer.new(app).bind("0.0.0.0", 8080).listenRadbas::Application is an HTTP::Handler, so it also works with HTTP::Server directly.
Put a Radbas::HeadHandler in front of it, so HEAD responses carry no body (ApplicationServer does this):
HTTP::Server.new([Radbas::HeadHandler.new, app]).listen(8080)Anything that satisfies Radbas::ActionLike is an action: a Proc(Radbas::Context, Nil) or a Radbas::Action.
class ShowUser
include Radbas::Action
def call(context : Radbas::Context) : Nil
context.response.print "User #{context.params["id"]}"
end
end
builder.get "/users/:id:d", ShowUser.new, name: "user"
# also head, post, put, patch, delete, options and map(method, path, action)
builder.group "/api" do |api|
api.add AuthMiddleware.new # runs for all routes of the group
api.get "/items", ListItems.new
end
# server-sent events
builder.sse "/events", ->(stream : Radbas::ServerSentEvents::Stream, context : Radbas::Context) {
stream.send(["hello"], event: "greeting")
}
# websocket
builder.ws "/socket", ->(socket : HTTP::WebSocket, context : Radbas::Context) {
socket.on_message { |message| socket.send(message) }
}See routing.cr for the path syntax. Named routes are built with the router:
router = Radbas::Routing::Router(Radbas::Action).new
builder = Radbas::ApplicationBuilder.new(router: router)
builder.get "/users/:id:d", ShowUser.new, name: "user"
router.build("user", {id: 42}) # => "/users/42"Requests to unknown paths get 404, wrong methods 405 with an Allow header. HEAD uses the GET route and
OPTIONS is answered with the allowed methods, unless a route for them exists.
Anything that satisfies Radbas::MiddlewareLike is middleware: a Proc(Radbas::Context, Radbas::Next, Nil) or a
Radbas::Middleware. A stdlib HTTP::Handler can be added as well.
class TimingMiddleware
include Radbas::Middleware
def call(context : Radbas::Context, delegate : Radbas::Next) : Nil
# before the action
delegate.call(context)
# after the action
end
end
builder.add TimingMiddleware.new
builder.add HTTP::CompressHandler.newGlobal middleware runs in the order it was added. build completes the chain:
add_request_logger_middleware: logs each request, not added by defaultadd_error_handler_middleware: turns exceptions into responses, added right after the logger if not added explicitly- your middleware
add_routing_middleware: matches the route, added last if not added explicitly- the route's group middleware and action
Built-in middleware: BodyParsingMiddleware (JSON, forms, multipart, size limit), CORSMiddleware,
SecureHeadersMiddleware, TrailingSlashMiddleware, PerformanceMiddleware.
Raise a Radbas::HTTPError to respond with an error status. The default CommonErrorHandler responds with JSON
and logs server errors. Other exceptions become a 500 without their message, unless show_details is set.
raise Radbas::HTTPError.new(:not_found)
raise Radbas::HTTPError.new(:unauthorized, headers: HTTP::Headers{"WWW-Authenticate" => "Bearer"})
builder.add_error_handler_middleware(Radbas::CommonErrorHandler.new(show_details: true))- Fork it (https://github.com/radbas/framework.cr/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
- Johannes Rabausch - creator and maintainer