Skip to content

feat(rpc): add zio-blocks-rpc descriptor foundation (#1143)#1270

Open
987Nabil wants to merge 7 commits into
zio:mainfrom
987Nabil:feat/rpc
Open

feat(rpc): add zio-blocks-rpc descriptor foundation (#1143)#1270
987Nabil wants to merge 7 commits into
zio:mainfrom
987Nabil:feat/rpc

Conversation

@987Nabil

@987Nabil 987Nabil commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a new zio-blocks-rpc module providing a derives RPC type class that captures service trait structure as a pure descriptor, analogous to how derives Schema captures data types.

Closes #1143

Design

trait UserService derives RPC:
  def getUser(id: Long): Either[UserError, User]

  @Idempotent
  def createUser(name: String, email: String): Either[UserError, User]

  def listUsers(): Either[UserError, List[User]]

  def health(): Status  // plain return, no error

RPC[T] captures method signatures, parameter schemas, success schemas, error schemas, and annotations at compile time. Protocol-specific artifacts derive from it via RpcDeriver[Protocol[_]], just like codec formats derive from Schema[A].

Key Design Decisions

  • No ZIO dependency — core rpc module depends only on schema
  • ReturnTypeDecomposer type class — effect/error decomposition stays extensible. Built-in support covers Either[E, A] and plain return types.
  • Cross-version — Scala 2.13 + 3.x shared API, with macro derivation on Scala 3 only
  • MetaAnnotation — extensible annotation infrastructure for service/method metadata
  • Transport-neutral JSON-RPC support — this PR derives a JsonRpcProtocol[T] contract plus a small reference binding to raw handlers for tests and lightweight integrations
  • Concrete runtimes stay out of blocks — Netty / Node / Wasm / browser server-client implementations can build on the derived contracts in downstream modules

What's Included

Component Description
RPC[T] Type class capturing service operations, schemas, and annotations
RPC.Operation[I, O] Per-operation metadata with Schema-backed I/O types
ReturnTypeDecomposer[F] Compile-time type class for effect type decomposition
MetaAnnotation Base class for service/method annotations
RpcDeriver[Protocol[_]] Trait for protocol-specific artifact derivation
RpcFormat Associates a protocol artifact with its deriver
JsonRpcProtocol[T] Transport-neutral JSON-RPC contract derived from RPC[T]
JsonRpcProtocol#bindHandlers Reference binding that validates one handler per operation and yields a low-level JsonRpcCodec
JsonRpcCodec Low-level JSON-RPC request dispatcher over raw handlers
42 tests Macro derivation + JSON-RPC integration coverage

Module Structure

rpc/shared/src/main/scala/        # Cross-version shared types
rpc/shared/src/main/scala-2/      # Scala 2 stubs (empty traits)
rpc/shared/src/main/scala-3/      # Macro derivation + version-specific
rpc/shared/src/test/scala-3/      # Tests (Scala 3 only)

Scope Boundary

This PR intentionally stops at the descriptor / protocol-contract layer inside blocks.

What it includes:

  • pure RPC descriptors
  • protocol artifact derivation
  • a reference JSON-RPC handler binding for tests and lightweight integrations

What it leaves for follow-up modules outside blocks:

  • production server runtimes
  • production client runtimes
  • transport implementations (Netty, Node, Wasm, browser, etc.)
  • DI-backed service execution wiring

Copilot AI review requested due to automatic review settings March 25, 2026 11:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new zio-blocks-rpc cross-project module that can derive an RPC[T] descriptor for service traits (Scala 3 macro), and includes a reference JSON-RPC 2.0 codec/deriver plus test coverage.

Changes:

  • Introduces core RPC descriptor types (RPC, RPC.Operation, metadata) and derivation hooks (RpcDeriver, RpcFormat, ReturnTypeDecomposer, MetaAnnotation).
  • Implements Scala 3 macro derivation for RPC.derived[T].
  • Adds JSON-RPC reference protocol support (JsonRpcCodec, JsonRpcDeriver, JsonRpcFormat) and Scala 3 tests + fixtures; wires module into build.sbt.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
rpc/shared/src/main/scala/zio/blocks/rpc/RPC.scala Core RPC[T] descriptor data model + derive convenience method.
rpc/shared/src/main/scala/zio/blocks/rpc/ReturnTypeDecomposer.scala Type class for extracting (error, success) from return types (e.g., Either).
rpc/shared/src/main/scala/zio/blocks/rpc/RpcDeriver.scala Protocol-derivation interface from RPC[T].
rpc/shared/src/main/scala/zio/blocks/rpc/RpcFormat.scala Format abstraction pairing a protocol type constructor with its deriver.
rpc/shared/src/main/scala/zio/blocks/rpc/annotations.scala MetaAnnotation base for RPC trait/method annotations.
rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcCodec.scala JSON-RPC 2.0 request/response handler (String => String).
rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcDeriver.scala Builds a JsonRpcCodec[T] from an RPC[T] descriptor.
rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcFormat.scala RpcFormat instance for JSON-RPC.
rpc/shared/src/main/scala-3/zio/blocks/rpc/RPCMacros.scala Scala 3 macro implementation for RPC.derived[T].
rpc/shared/src/main/scala-3/zio/blocks/rpc/RPCCompanionVersionSpecific.scala Scala 3 RPC.derived inline entrypoint.
rpc/shared/src/main/scala-3/zio/blocks/rpc/RPCVersionSpecific.scala Scala 3 version-specific trait placeholder.
rpc/shared/src/main/scala-2/zio/blocks/rpc/RPCCompanionVersionSpecific.scala Scala 2 stub (no macro derivation).
rpc/shared/src/main/scala-2/zio/blocks/rpc/RPCVersionSpecific.scala Scala 2 version-specific trait placeholder.
rpc/shared/src/test/scala-3/zio/blocks/rpc/RPCMacroSpec.scala Scala 3 tests for macro-derived RPC descriptors and schemas.
rpc/shared/src/test/scala-3/zio/blocks/rpc/fixtures/TestFixtures.scala Test data types, annotations, and service traits used by specs.
rpc/shared/src/test/scala-3/zio/blocks/rpc/jsonrpc/JsonRpcIntegrationSpec.scala JSON-RPC integration tests for request/response behavior + derivation.
build.sbt Adds rpc module, hooks into test/doc aliases, sets coverage config.

Comment thread rpc/shared/src/main/scala-3/zio/blocks/rpc/RPCMacros.scala Outdated
Comment thread rpc/shared/src/main/scala/zio/blocks/rpc/ReturnTypeDecomposer.scala
Comment thread rpc/shared/src/test/scala-3/zio/blocks/rpc/fixtures/TestFixtures.scala Outdated
Comment thread rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcCodec.scala Outdated
Comment thread rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcCodec.scala Outdated
Comment thread rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcCodec.scala Outdated
Comment thread rpc/shared/src/main/scala/zio/blocks/rpc/jsonrpc/JsonRpcCodec.scala
@987Nabil 987Nabil force-pushed the feat/rpc branch 2 times, most recently from c75d578 to 6e38b80 Compare April 23, 2026 05:24
@github-actions

github-actions Bot commented Apr 23, 2026

Copy link
Copy Markdown

🚀 Preview deployed to Netlify: https://zio-blocks-pr-1270--zio-dev.netlify.app

@987Nabil 987Nabil force-pushed the feat/rpc branch 3 times, most recently from 4a21ee8 to b869db7 Compare April 27, 2026 09:14
@987Nabil 987Nabil changed the title feat(rpc): add zio-blocks-rpc module with derives RPC type class (#1143) feat(rpc): add zio-blocks-rpc descriptor foundation (#1143) Apr 30, 2026
@987Nabil 987Nabil force-pushed the feat/rpc branch 3 times, most recently from 4121640 to 3e88856 Compare May 6, 2026 12:54
987Nabil added 7 commits May 29, 2026 16:59
Adds a new zio-blocks-rpc module providing a derives RPC type class that
captures service trait structure as a pure data representation, analogous
to how derives Schema works for data types.

- RPC[T] type class with Operation descriptors and Schema-backed I/O types
- ReturnTypeDecomposer type class for flexible effect type support
- Built-in Either[E, A] decomposition; plain types fallback to no error
- MetaAnnotation for service/method/parameter-level metadata
- RpcDeriver[Protocol[_]] and RpcFormat for protocol derivation
- JSON-RPC 2.0 reference protocol with spec-compliant handling
- Cross-compiles for Scala 2.13 + 3.x (macro derivation Scala 3 only)
- 39 tests (macro derivation + JSON-RPC integration)

Closes zio#1143
Copilot AI review requested due to automatic review settings June 4, 2026 20:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 19 changed files in this pull request and generated 4 comments.

Comment on lines +90 to +98
handle = params => {
val typedInput = operation.inputCodec.asInstanceOf[JsonCodec[Input]].decodeValue(params)
try {
handler(typedInput)
.map(output => operation.outputCodec.asInstanceOf[JsonCodec[Output]].encodeValue(output))
} catch {
case NonFatal(error) => Left(SchemaError(error.getMessage))
}
}
Comment on lines +65 to +71
/**
* Binds a single typed operation handler and produces an executable codec.
*
* This reference binding keeps the public API in terms of typed values plus
* the derived operation schemas/codecs, while raw JSON remains internal to
* the wire format boundary.
*/
Comment on lines +121 to +123
private[jsonrpc]
/** Internal raw JSON handler after typed binding. */
final case class BoundOperation(
Comment on lines +108 to +116
test("MultiAnnotatedService - multiple annotations on same method") {
val rpc = RPC.derived[MultiAnnotatedService]
val op = rpc.operations(0)
assertTrue(
op.annotations.length == 2,
op.annotations.exists(_.isInstanceOf[Idempotent]),
op.annotations.exists(_.isInstanceOf[RpcDeprecated])
)
}
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.

zio-blocks-rpc: RPC type class for service trait introspection (derives RPC)

2 participants