You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/asciidoc/modules/json-rpc.adoc
+84Lines changed: 84 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -105,6 +105,90 @@ Supported engines include:
105
105
106
106
No additional configuration is required. The generated dispatcher automatically hooks into the installed engine using the `JsonRpcParser` and `JsonRpcDecoder` interfaces, ensuring primitive types are strictly validated and parsed.
107
107
108
+
=== Middleware Pipeline
109
+
110
+
Jooby provides a dedicated middleware architecture for JSON-RPC using the `JsonRpcInvoker` and `JsonRpcChain` APIs. This allows you to intercept RPC calls to apply cross-cutting concerns like logging, security, metrics, or tracing.
111
+
112
+
To create an interceptor, implement the `JsonRpcInvoker` interface.
113
+
114
+
.JSON-RPC
115
+
[source,java,role="primary"]
116
+
----
117
+
import io.jooby.jsonrpc.*;
118
+
import java.util.Optional;
119
+
120
+
public class LoggingInvoker implements JsonRpcInvoker {
121
+
122
+
@Override
123
+
public Optional<JsonRpcResponse> invoke(Context ctx, JsonRpcRequest request, JsonRpcChain next) {
ctx.getLog().warn("RPC {} failed in {}ms", request.getMethod(), took);
135
+
} else {
136
+
ctx.getLog().info("RPC {} succeeded in {}ms", request.getMethod(), took);
137
+
}
138
+
});
139
+
140
+
return response;
141
+
}
142
+
}
143
+
----
144
+
145
+
.Kotlin
146
+
[source,kotlin,role="secondary"]
147
+
----
148
+
import io.jooby.jsonrpc.*
149
+
import java.util.Optional
150
+
151
+
class LoggingInvoker : JsonRpcInvoker {
152
+
153
+
override fun invoke(ctx: Context, request: JsonRpcRequest, next: JsonRpcChain): Optional<JsonRpcResponse> {
154
+
val start = System.currentTimeMillis()
155
+
156
+
// Proceed down the chain
157
+
val response = next.proceed(ctx, request)
158
+
159
+
val took = System.currentTimeMillis() - start
160
+
161
+
// Inspect the response
162
+
response.ifPresent { res ->
163
+
if (res.error != null) {
164
+
ctx.log.warn("RPC {} failed in {}ms", request.method, took)
165
+
} else {
166
+
ctx.log.info("RPC {} succeeded in {}ms", request.method, took)
167
+
}
168
+
}
169
+
170
+
return response
171
+
}
172
+
}
173
+
----
174
+
175
+
You register invokers fluently when installing the `JsonRpcModule`. You can chain multiple invokers together, and they will execute in the order they are added.
176
+
177
+
[source,java]
178
+
----
179
+
install(new JsonRpcModule(new MovieServiceRpc_())
180
+
.invoker(new SecurityInvoker())
181
+
.invoker(new LoggingInvoker()));
182
+
----
183
+
184
+
==== Safe Exception Handling
185
+
Notice that you **do not** need to wrap `next.proceed()` in a `try-catch` block. The final executor in the JSON-RPC pipeline acts as an ultimate safety net. It catches all unhandled exceptions, protocol failures (like Parse Errors), and routing failures, safely transforming them into a standard `JsonRpcResponse` containing an `ErrorDetail`.
186
+
187
+
To react to failures in your middleware, simply inspect `response.get().getError() != null`.
188
+
189
+
==== Notifications and Optional Responses
190
+
The invocation pipeline returns an `Optional<JsonRpcResponse>`. This is because the JSON-RPC 2.0 specification explicitly dictates that **Notifications** (requests sent without an `id` member) must not receive a response. For these requests, the chain will safely execute the target method but return `Optional.empty()`.
191
+
108
192
=== Error Mapping
109
193
110
194
Jooby seamlessly bridges standard Java application exceptions and HTTP status codes into the JSON-RPC 2.0 format using the `JsonRpcErrorCode` mapping. You do not need to throw custom protocol exceptions for standard failures.
Provides automatic tracing for your JSON-RPC 2.0 endpoints. By adding the `OtelJsonRcpTracing` middleware to your JSON-RPC pipeline, it generates a dedicated OpenTelemetry span for every RPC invocation.
290
+
291
+
It automatically records standard semantic attributes (such as `rpc.system`, `rpc.method`, and `rpc.jsonrpc.request_id`). Furthermore, because it hooks directly into the `JsonRpcChain`, it accurately records protocol errors and application failures by inspecting the `JsonRpcResponse` envelope, without relying on thrown exceptions.
Seamlessly exports all application logs to your OpenTelemetry backend, automatically correlated with active trace and span IDs using a dynamic appender.
0 commit comments