Handler callbacks
Callbacks enable you to define logic that is triggered at different stages of a handler's lifecycle. This feature allows you to intercept incoming requests and potentially bypass the standard #dispatch
method. This document covers the available callbacks and introduces you to the associated API, which you can use to define hooks in your handlers.
Overview
As stated above, callbacks are methods that will be called when specific events occur for a specific handler instance. They need to be registered explicitly in your handler classes. There are many types of of callbacks: some are shared between all types of handlers while some others are specific to some kinds of generic handlers. For most types of callbacks, it is generally possible to register "before" or "after" callbacks.
Registering a callback is as simple as calling the right callback macro (eg. #before_dispatch
) with a symbol of the name of the method to call when the callback is executed.
For example, the following handler leverages the #before_dispatch
callback in order to redirect the user to a login page if they are not already authenticated:
class MyHandler < Marten::Handler
before_dispatch :require_authenticated_user
def get
respond "Hello, authenticated user!"
end
private def require_authenticated_user
redirect(login_url) unless user_authenticated?(request)
end
end
Shared handler callbacks
The following callbacks are shared between all types of handlers.
before_dispatch
before_dispatch
callbacks are executed before a request is processed as part of the handler's #dispatch
method. For example, this capability can be leveraged to inspect the incoming request and verify that a user is logged in:
class MyHandler < Marten::Handler
before_dispatch :require_authenticated_user
def get
respond "Hello, authenticated user!"
end
private def require_authenticated_user
redirect(login_url) unless user_authenticated?(request)
end
end
When one of the defined before_dispatch
callbacks returns a Marten::HTTP::Response
object (like this is the case in the above example), this response is always used instead of calling the handler's #dispatch
method (the latest is thus completely bypassed).
after_dispatch
after_dispatch
callbacks are executed after a request is processed as part of the handler's #dispatch
method. For example, such a callback can be leveraged to automatically add headers or cookies to the returned response.
class MyHandler < Marten::Handler
after_dispatch :add_required_header
def get
respond "Hello, authenticated user!"
end
private def add_required_header : Nil
response!.headers["X-Foo"] = "Bar"
end
end
Similarly to #before_dispatch
callbacks, #after_dispatch
callbacks can return a brand new Marten::HTTP::Response
object. When this is the case, this response is always used instead of the one that was returned by the handler's #dispatch
method.
before_render
before_render
callbacks are invoked prior to rendering a template when generating a response that incorporates its content. This means that these callbacks are executed as part of the #render
helper method and when rendering templates as part of subclasses of the Marten::Handlers::Template
generic handler.
Typically, these callbacks are used to add new variables to the global template context, in order to make them accessible to the template runtime. For example:
class MyHandler < Marten::Handlers::Template
template_name "app/my_template.html"
before_render :add_variable_to_context
private def add_variable_to_context : Nil
context["foo"] = "bar"
end
end
Note that before_render
callbacks can technically be used to return a Marten::HTTP::Response
object. When this situation arises, this response always takes precedence over the one that would've been returned following the rendering of the template.
Schema handler callbacks
The following callbacks are only available for handlers that inherit from the schema handler. That is, handlers that inherit from Marten::Handlers::Schema
, but also handlers that inherit from Marten::Handlers::RecordCreate
and Marten::Handlers::RecordUpdate
.
These callbacks let you define logics that are triggered before or after the validation of the schema. This allows you to easily intercept validation and handle the response independently of the schema validity. All these callbacks can optionally return a Marten::HTTP::Response
object. When an HTTP response is returned,
all following callbacks are skipped and the obtained response is returned directly, thus bypassing responses that might have been returned after by the handler.
before_schema_validation
before_schema_validation
callbacks are executed before a schema is checked for validity. For example, this capability can be leveraged to set an attribute on the schema object before the schema validity is checked:
class ArticleCreateHandler < Marten::Handlers::Schema
success_url "https://example.com/articles/list"
template_name "articles/create.html"
schema ArticleSchema
before_schema_validation :prepare_schema
private def prepare_schema
schema.user = request.user
end
end
after_schema_validation
after_schema_validation
callbacks are executed right after a schema is checked for validity. For example, this capability can be leveraged to call a custom method on the schema instance:
class ArticleCreateHandler < Marten::Handlers::Schema
success_url "https://example.com/articles/list"
template_name "articles/create.html"
schema ArticleSchema
after_schema_validation :run_schema_post_validation
private def run_schema_post_validation : Nil
schema.trigger_post_something
end
end
after_successful_schema_validation
after_successful_schema_validation
callbacks are executed right after a schema is checked for validity (and after possible after_schema_validation
callbacks), and only if the schema validation was successful.
For example, this capability can be leveraged to create a flash message:
class ArticleCreateHandler < Marten::Handlers::Schema
success_url "https://example.com/articles/list"
template_name "articles/create.html"
schema ArticleSchema
after_successful_schema_validation :generate_success_flash_message
private def generate_success_flash_message : Nil
flash[:notice] = "Article successfully created!"
end
end
after_failed_schema_validation
after_failed_schema_validation
callbacks are executed right after a schema is checked for validity (and after possible
after_schema_validation
callbacks), but only if the schema validation failed. For example, this capability can be leveraged to create a flash message:
class ArticleCreateHandler < Marten::Handlers::Schema
success_url "https://example.com/articles/list"
template_name "articles/create.html"
schema ArticleSchema
after_failed_schema_validation :generate_failure_flash_message
private def generate_failure_flash_message : Nil
flash[:notice] = "Article creation failed!"
end
end