Skip to content

Instantly share code, notes, and snippets.

@jgaskins
Created August 10, 2019 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jgaskins/cdc6084f265e6e12f9d4357d118ec7cd to your computer and use it in GitHub Desktop.
Save jgaskins/cdc6084f265e6e12f9d4357d118ec7cd to your computer and use it in GitHub Desktop.
Roda-like web framework in Crystal
class App
# Provides the `call(context : HTTP::Server::Context)` interface
include HTTP::Handler
# Provides the `route` method that we pass the context to to be
# able to use routing and response data
include Route
def call(context : HTTP::Server::Context)
route context do |r, response, session|
# We render the top part of the app separately because ECR
# doesn't have a clean way to render a template within other
# template without allocating a big intermediate string on the
# heap containing the app's main body markup. Rendering them
# sequentially allows us to skip that extra allocation and
# use that memory and allocation/GC time to service other
# requests.
ecr_render "app_header"
# Ensure that we send the body to the browser immediately so
# it can begin fetching stylesheets while we're rendering the
# rest of the page.
response.flush
# The `ecr_render` macro renders the specified ECR template
# (from the `views` directory) into our response. If we call the
# response variable `response` in our block params for `route`,
# we can omit it here as we did above for `"app_header"`.
r.root { ecr_render "index", to: response }
# Delegate routes to other "apps" that just render body content.
# From their perspective, the path will have the matched portion
# removed, so in this example, routing `/orders/123` would
# expose the path as `/123` to the Orders route.
r.on "orders" { Orders.new.call context }
r.on "whatever" { Whatever.new.call context }
# Render a 404 page if no other routes picked this up
r.miss { ecr_render "not_found" }
# Render the app footer
ecr_render "app_footer"
end
end
end
server = HTTP::Server.new([
HTTP::LogHandler.new,
App.new,
])
server.listen 8080
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment