Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a before_send middleware feature in development mode for better tooling integration #343

Open
samueleaton opened this issue Mar 28, 2017 · 6 comments

Comments

@samueleaton
Copy link
Contributor

samueleaton commented Mar 28, 2017

I'd like to be able to make some development tooling that integrates with Kemal. One needed feature is the ability to access the HTTP context right before it is sent to the client (after the route handler) so that the tools can do extra things (e.g. inject a special websocket script into the html body).

If we add a macro that checks for KEMAL_ENV at compile time we can add before_respond_handler checker.

This could be added to the process_request method in the route_handler.cr file like so:

private def process_request(context)
  raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined?
  route = context.route_lookup.payload.as(Route)
  content = route.handler.call(context)
ensure
  remove_tmpfiles(context)
  if Kemal.config.error_handlers.has_key?(context.response.status_code)
    raise Kemal::Exceptions::CustomException.new(context)
  end
  context.response.print(content)
  
  # before_send macro here
  {% unless env("KEMAL_ENV") == "production" %}
    # this is where you would check if there are any before_send middlewares set
    puts "allow before_respond handlers to modify context before sending: ", context
  {% end %}

  context
end

The point is to be able to create more tools for development mode. This will have absolutely zero effect on performance in production mode because the macro won't add any code in production.

The phoenix framework (elixir), for example, does a similar check in development mode for live code reloading. This would allow for more tooling to solve problems as in #335

Thank you!

@sdogruyol
Copy link
Member

This sounds interesting @samueleaton, i'm OK for this if it's all compile time and no performance penalty for production apps 👍

@samueleaton
Copy link
Contributor Author

samueleaton commented Mar 28, 2017

@sdogruyol Sweet. I'll make a WIP branch and will discuss with you further how to we should go about adding a before_respond_handler or before_send_handler middleware for development.

@sdogruyol
Copy link
Member

before_respond_handler sounds fine 👍

@samueleaton
Copy link
Contributor Author

Its looking like the response is a write-only IO. So is it possible to read from it?

@faustinoaq
Copy link
Contributor

Hi, this could be a good feature!

I created a Kemal-watcher plugin to use with Kemal in development environments, helping to reload the browser when a file change occur. This plugin is very basic, it just add a new handler and does context.response.print but works 😅

@crisward
Copy link
Contributor

crisward commented Oct 1, 2017

As @samueleaton pointed out, the response is write-only io. It can't be read or modified because it's probably already been sent to the client. The only way to achieve this would be to buffer the output, to allow it to be modified before being added to response.

This is possible when the response is a return value from a route, but if it's being piped directory into the response, I'm not sure.

If the above restriction is ok, this could be added here
https://github.com/kemalcr/kemal/blob/master/src/kemal/route.cr#L11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants