Skip to content

feat(grpc): add ServerBuilder, registration, interceptors, and routing - #2789

Open
sauravzg wants to merge 2 commits into
masterfrom
sauravz/server-builder-api
Open

feat(grpc): add ServerBuilder, registration, interceptors, and routing#2789
sauravzg wants to merge 2 commits into
masterfrom
sauravz/server-builder-api

Conversation

@sauravzg

@sauravzg sauravzg commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Introduce the server-side handle/router API for building a gRPC Server from a fluent builder.

  • ServerBuilder: fluent construction via Server::builder(), with add_service, interceptorand build.
  • Service + ServiceExt: Service trait for method registration, plus with_interceptor to wrap all of a service's methods (InterceptedService).
  • Interceptors: Intercept trait, no-op Identity, and InterceptExt::chain for composing interceptors into an InterceptorChain (first added runs outermost).
  • Descriptors: ServiceDescriptor, MethodDescriptor, and MethodType.
  • Routing: RouterBuilder maps method paths to DynHandles.
  • Options: ServerOptions currently empty, but a kitchen sink for options.

@sauravzg
sauravzg force-pushed the sauravz/server-builder-api branch from f7320bc to 98ab999 Compare August 4, 2026 14:51
@sauravzg
sauravzg marked this pull request as ready for review August 4, 2026 15:44
@sauravzg
sauravzg requested a review from dfawley August 4, 2026 15:44
@sauravzg
sauravzg force-pushed the sauravz/server-builder-api branch from 98ab999 to a682691 Compare August 6, 2026 16:04
@sauravzg
sauravzg force-pushed the sauravz/server-builder-api branch 2 times, most recently from 74c4469 to cbedd8d Compare August 11, 2026 10:37
Base automatically changed from sauravz/server-transport-api to master August 11, 2026 11:16
Introduce the server-side handle/router API for building a gRPC `Server`
from a fluent builder.

- ServerBuilder: fluent construction via `Server::builder()`, with
  `add_service`, `interceptor`and `build` / `build_with_runtime`.
- Service + ServiceExt: `Service` trait for method registration, plus
  `with_interceptor` to wrap all of a service's methods
  (InterceptedService).
- Interceptors: `Intercept` trait, no-op `Identity`, and
  `InterceptExt::chain` for composing interceptors into an
  `InterceptorChain` (first added runs outermost).
- Descriptors: `ServiceDescriptor`, `MethodDescriptor`, and
  `MethodType`.
- Routing: `RouterBuilder` maps method paths to `DynHandle`s.
- Options: `ServerOptions` currently empty, but a kitchen sink for
  options.
@sauravzg
sauravzg force-pushed the sauravz/server-builder-api branch from cbedd8d to f3ce938 Compare August 11, 2026 11:16
Comment thread grpc/src/server/builder.rs Outdated

/// The type (cardinality) of a gRPC method.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MethodType {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we would hide this from grpc itself and let it treat everything as bidi streaming?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I missed addressing this yesterday. I agree in principle but I think we have precedent at least in java and very likely c++(but not c-core), where the descriptors are a part of interceptor API and support a notion of method type.

Slighly confused about go , but you probably know better about it.

Given, that this is very useful information to have about an RPC, I am leaning towards the Java-ish approach which would essentially be adding another enum named "unknown" here and be done with it.

rx: impl RecvStream + 'static,
next: &impl Handle,
) -> Trailers {
next.handle(headers, options, tx, rx).await

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With optimizations on, does this cause literally no overhead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't confirm this , but I don't see a reason why. It's a zero sized type with no allocations and I'd assume the compiler can inline this to make it no-op.

Should we add a microbenchmark for this?

Comment thread grpc/src/server/mod.rs Outdated
Comment on lines +197 to +198
/// Creates a new server with the given handler, runtime, and options.
pub(crate) fn new(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we delete new and require the use of the builder?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new is pub(crate) , the only public way to construct is via the builder which on build calls this new.

Are we looking for something different?

Comment thread grpc/src/server/mod.rs Outdated
Comment thread grpc/src/server/router.rs Outdated
use crate::server::service::Service;

/// A builder for constructing an immutable [`Router`].
pub(crate) struct RouterBuilder<I = Identity> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why not use a default type for ServerBuilder, too? I assume this is here so that you can impl RouterBuilder instead of needing to impl RouterBuilder<Identity>?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ServerBuilder is already default typed. The chain of default types was keeping everything similar .

Anyways, followed the call chain and realized that it's not needed, since the way it's modelled right now is to chain interceptors and the only public entrypoint is Server::builder(), having default type on ServerBuilder combined with impl RouterBuilder<Identity> should be good enough.

Comment thread grpc/src/server/router.rs Outdated
Comment thread grpc/src/server/builder.rs Outdated
///
/// # Examples
///
/// ```ignore

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if we could avoid ignore for our examples. Especially as we're heavily iterating on things, there's a high likelihood that they will become broken this way. Please use other tags instead like no_run or use leading # to hide things from the rendered documentation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided to remove most of the doc tests. Didn't see a huge value in the ones with no_run .
Fixing them right now would make a bunch of symbols public which I would want to avoid until it's needed.

Comment thread grpc/src/server/builder.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants