-
Notifications
You must be signed in to change notification settings - Fork 60
Service Hooks
Mario Izquierdo edited this page Apr 16, 2019
·
3 revisions
Hooks allow injecting useful code during the lifecycle of a Twirp server request.
routing -> before -> handler -> on_success
-> on_error
One and only one of on_success
or on_error
is called per request. If exceptions are raised, the exception_raised
hook is called before calling on_error
.
routing -> before -> handler
! exception_raised -> on_error
-
before: (block
|rack_env, env|
) Runs after the request is routed to an rpc method, but before calling the method handler. This is the only place to read therack_env
to access http request and middleware data, and can add more values to the Twirpenv
, for example authentication data likeenv[:user_id]
. The Twirpenv
already has some routing info likeenv[:rpc_method]
,env[:input]
and env[:input_class]
. Returning aTwirp::Error
from the before hook immediately cancels the request. -
on_success: (block
|env|
) Runs after the rpc method is handled, unless it returned aTwirp:Error
or raised an exception. Theenv[:output]
contains the serialized message of classenv[:ouput_class]
. -
on_error: (block
|twerr, env|
) Runs on error responses, that isbad_route
errors during routing, Twirp errors returned from before hooks or method handlers, or after an exception was raised. Raised exceptions are wrapped withTwirp::Error.internal_with(e)
, that has codeinternal
and the original exception is stored intwerr.cause
. -
exception_raised: (block
|e, env|
) Runs if an exception was raised from the handler or any of the other hooks.
svc = Example::HelloWorldService.new(handler)
svc.before do |rack_env, env|
env[:user_id] = authenticate(rack_env)
env[:enviornment] = (ENV['ENVIRONMENT'] || :local).to_sym
end
svc.on_success do |env|
Stats.inc("requests.success")
end
svc.on_error do |twerr, env|
Stats.inc("requests.error.#{twerr.code}")
end
svc.exception_raised do |e, env|
if env[:environment] == :local
puts "[Exception] #{e}"
puts e.backtrace.join("\n")
else
ExceptionTracker.send(e)
end
end
If for some reason you need to run code before the Twirp service routes the request, then you should use standard Rack Middleware.
For example:
class MyMiddleware
def initialize(app)
@app = app
end
def call(rack_env)
# do some stuff and decide to return an early Twirp error
if not_cool(env)
twerr = Twirp::Error.invalid_argument("not cool", foo: "bar-meta")
return Twirp::Service.error_response(twerr)
end
rack_env["mystaff"] = "foobar" # this is available in before hooks
@app.call(rack_env)
end
end
A Twirp::Service
is also Rack Middleware, and the before
hook has access to the rack_env
. If your middleware adds data into the rack_env
, that will be available in the before
hook. The before
hook could also add it to the Twirp env
, so that data is also available in method handlers.