Skip to content

middleware: RpcServiceT distinct return types for notif, batch, call #1564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 23, 2025

Conversation

niklasad1
Copy link
Contributor

@niklasad1 niklasad1 commented Apr 19, 2025

This PR modifies to RpcServiceT to:

pub trait RpcServiceT {
	/// Response type for `RpcServiceT::call`.
	type MethodResponse: ToJson;
	/// Response type for `RpcServiceT::notification`.
	type NotificationResponse: ToJson;
	/// Response type for `RpcServiceT::batch`.
	type BatchResponse: ToJson;

	/// Processes a single JSON-RPC call, which may be a subscription or regular call.
	fn call<'a>(&self, request: Request<'a>) -> impl Future<Output = Self::MethodResponse> + Send + 'a;

	/// Processes multiple JSON-RPC calls at once, similar to `RpcServiceT::call`.
	///
	/// This method wraps `RpcServiceT::call` and `RpcServiceT::notification`,
	/// but the root RPC service does not inherently recognize custom implementations
	/// of these methods.
	///
	/// As a result, if you have custom logic for individual calls or notifications,
	/// you must duplicate that implementation in this method or no middleware will be applied
	/// for calls inside the batch.
	fn batch<'a>(&self, requests: Batch<'a>) -> impl Future<Output = Self::BatchResponse> + Send + 'a;

	/// Similar to `RpcServiceT::call` but processes a JSON-RPC notification.
	fn notification<'a>(&self, n: Notification<'a>) -> impl Future<Output = Self::NotificationResponse> + Send + 'a;
}

This is an improvement because it's now possible to return different futures for the async operations but the downside is that it's harder to chain error because it's not an associated type anymore.

Thus, for instance in the client-side impls we are wrapping the responses in Result<T, E> where the concrete error type must be returned instead of E: Into`

@niklasad1 niklasad1 requested a review from a team as a code owner April 19, 2025 13:31
@niklasad1 niklasad1 requested a review from Copilot April 19, 2025 13:31
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the RpcServiceT trait and its implementations by introducing distinct associated types for handling method calls, batch requests, and notifications. The key changes include:

  • Replacing signature return types from Result<Self::Response, Self::Error> to direct types (Self::MethodResponse, Self::BatchResponse, and Self::NotificationResponse).
  • Adjusting all RpcServiceT implementations and related usage in tests, server, middleware layers, and client components.
  • Updating the middleware and client layers to work with the new response type conventions.

Reviewed Changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated no comments.

Show a summary per file
File Description
server/src/tests/http.rs Updated RpcServiceT implementation in tests to use unique ret types for futures.
server/src/server.rs Adjusted builder examples and type constraints in server configuration to match new RpcServiceT definitions.
server/src/middleware/rpc.rs Reworked middleware response handling to remove the Result<> wrapper.
examples/* Modified examples to align RpcServiceT signature changes and update middleware/client usage.
core/src/middleware/* Refactored RpcServiceT trait and related layers to reflect the new response types.
client/* Updated HTTP and asynchronous client implementations to use the revised RpcServiceT return types.

@niklasad1 niklasad1 changed the title middleware: RpcServiceT unique ret tys for futures middleware: RpcServiceT distinct return types for notif, batch, call Apr 20, 2025
&self,
n: Notification<'a>,
) -> impl Future<Output = Result<Self::Response, Self::Error>> + Send + 'a;
fn notification<'a>(&self, n: Notification<'a>) -> impl Future<Output = Self::NotificationResponse> + Send + 'a;
}

/// Interface for types that can be serialized into JSON.
Copy link
Collaborator

@jsdw jsdw Apr 23, 2025

Choose a reason for hiding this comment

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

Nit: I'd be tempted to put this with the logger middleware since that's where it's used, and then have the impls on specific types right next to it. That'll make it clear what the logger middleware will work with right off the bat :)

(other people can / may wish to define their own traits to do similar things to allow for generic middlewares, rather than rely on things like ToJson for their needs)

#[derive(Clone)]
struct Identity<S>(S);

impl<S> RpcServiceT for Identity<S>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice how easy it is to impl this sort of thing with 0 overhead now :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

(Though I realise this is because of the impl Future and not the splitting of return types!)

Copy link
Collaborator

@jsdw jsdw left a comment

Choose a reason for hiding this comment

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

Nice! Just a couple of tiny nits :)

@niklasad1 niklasad1 requested a review from Copilot April 23, 2025 13:27
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the RpcServiceT trait to allow distinct future types for calls, notifications, and batches by replacing a single Result‐wrapped associated response with three separate associated types. Key changes include:

  • Removing the generic error type from RpcServiceT and updating all related implementations (server, client, middleware, and examples) to return direct response types.
  • Propagating these type changes across the codebase (including async response handling using ResponseFuture::ready and ResponseFuture::future) to simplify chaining and error handling.

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated no comments.

Show a summary per file
File Description
server/src/middleware/rpc.rs Refactored RpcServiceT implementation with separate associated response types.
proc-macros/tests/ui/correct/basic.rs Updated test definitions to align with the new RpcServiceT associated types.
examples/* Adjusted example implementations to accommodate the new async response patterns.
core/src/* Updated core traits, client, and middleware implementations to remove error wrapping.
client/* Adapted client and HTTP client modules to use MiddlewareMethodResponse and related types.
Comments suppressed due to low confidence (2)

core/src/client/async_client/rpc_service.rs:82

  • [nitpick] Consider using a dedicated setter or helper method to update the response's extensions instead of directly mutating the field. This can improve encapsulation and ease future maintenance.
rp.0.extensions = request.extensions.clone();

core/src/middleware/mod.rs:298

  • Update or expand the documentation/comments for RpcServiceT to clearly indicate that the trait no longer returns a Result-wrapped response. This clarification will help consumers of the trait adapt to the breaking change in error handling.
pub trait RpcServiceT {

@niklasad1 niklasad1 merged commit a9a8f6d into master Apr 23, 2025
10 checks passed
@niklasad1 niklasad1 deleted the na-middleware-multi-ret-tys branch April 23, 2025 13:55
@niklasad1 niklasad1 mentioned this pull request Apr 23, 2025
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