Skip to content

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

Open
sauravzg wants to merge 1 commit into
masterfrom
sauravz/server-builder-api
Open

feat(grpc): add ServerBuilder, registration, interceptors, and routing#2789
sauravzg wants to merge 1 commit 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
/// # Examples
///
/// ```ignore
/// let server = Server::builder()

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.

We have both ServerBuilder::new() and Server::builder()? Why?


/// 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?

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?

Comment thread grpc/src/server/mod.rs
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?

Comment thread grpc/src/server/mod.rs
}

/// Returns the server options.
pub fn options(&self) -> &ServerOptions {

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.

What is this for?

Comment thread grpc/src/server/router.rs
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>?

Comment thread grpc/src/server/router.rs
/// .add_service(my_service)
/// .build();
/// ```
pub struct Router<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.

This one I can't see why there's a default type?

///
/// # 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.

use crate::server::SendStream;
use crate::server::Server;
use crate::server::Trailers;
use crate::server::descriptor::{MethodDescriptor, MethodType, ServiceDescriptor};

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.

Please rustfmt to ungroup imports:

rustfmt --edition=2024 --config imports_granularity=Item --config group_imports=StdExternalCrate <files>

or inside the grpc crate, this will get everything:

cargo fmt -- --config imports_granularity=Item --config group_imports=StdExternalCrate

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