Your opinion will help to improve our service
Leave a feedback >There are two main interfaces for implementing a middleware:
Methods ugrpc::server::MiddlewareBase::OnCallStart and ugrpc::server::MiddlewareBase::OnCallFinish are called once per grpc Call (RPC).
OnCallStart
is called after the client metadata is received. OnCallFinish
is called before the last message is sent or before error status is sent to a client.
OnCallStart
hooks are called in the order of middlewares. OnCallFinish
hooks are called in the reverse order of middlewares
Register the component.
The static YAML config.
You can add some behavior on each request/response. Especially, it can be important for grpc-stream. See about streams in gRPC.
PostRecvMessage
hooks are called in the direct middlewares order. PreSendMessage
hooks are called in the reversed order.
For more information about the middlewares order:
The static YAML config.
Register the middleware component in the component system.
We use a simple short-cut ugrpc::server::SimpleMiddlewareFactoryComponent in the example above. To declare static config options of your middleware see gRPC middlewares configuration.
To fully understand what happens when middlewares hooks fail, you should understand the middlewares order:
If you want to interrupt a Call (RPC) in middlewares, you should use ugrpc::server::MiddlewareCallContext::SetError (see examples above on this page).
If you throw an exception in middlewares hooks, that exception will be translated to grpc::Status
(by default grpc::StatusCode::UNKNOWN
) and next hooks won't be called. server::handlers::CustomHandlerException is translated to a relevant grpc::Status
.
All errors will be logged just like an exception or error status from the user handler:
error_msg
tag.SetError
.ugrpc::server::MiddlewareBase::OnCallFinish will be called despite of any errors.
The actual status is passed to OnCallFinish
hooks. Each OnCallFinish
hook gets the status from a previous OnCallFinish
call and can change that by SetError
(or exception). An error status from a handler will be passed to a first OnCallFinish
and that hook can change that status, next hooks will get the new status. If all OnCallFinish
hooks don't change the status, that status will be the final status for a client.
There are 3 middlewares A
, B
, C
. Cases:
A::OnCallStart
and B::OnCallStart
succeed, but C::OnCallStart
fails (by SetError
or exception) ⇒ B::OnCallFinish
and A::OnCallFinish
will be called (remember that OnCallFinish
order is reversed).OnCallStart
succeed and C::OnCallFinish
fails, B::OnCallStart
and A::OnCallStart
will be called and these hooks get an error status from C::OnCallFinish
.OnCallFinish
will be called.PostRecvMessage
/PreSendMessage
⇒ RPC is failed ⇒ all OnCallFinish
hooks will be called.There are two ways to implement a middleware component. You can see above ugrpc::server::SimpleMiddlewareFactoryComponent. This component is needed for simple cases without static config options of a middleware.
kName
and kDependency
(middlewares::MiddlewareDependencyBuilder) must be in a middleware class (as shown above).If you want to use static config options for your middleware, use ugrpc::server::MiddlewareFactoryComponentBase.
To override static config options of a middleware per a server see grpc_middlewares_config_override.
Before starting to read specifics of server middlewares ordering:
There are simple cases above: we just set Auth
group for one middleware and use a default constructor of MiddlewareDependencyBuilder
in other middleware. Here we say that all server middlewares are located in these groups.
PreCore
group is called firstly, then Logging
and so forth...