@funduck/connectrpc-fastify 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +102 -10
  2. package/package.json +3 -2
package/README.md CHANGED
@@ -5,12 +5,10 @@ Code is not production ready.
5
5
 
6
6
  ## Description
7
7
 
8
- This is a wrapper for [Connectrpc](https://github.com/connectrpc/connect-es) using the [Fastify](https://github.com/fastify/fastify) server.
9
-
8
+ This is a wrapper for [Connectrpc](https://github.com/connectrpc/connect-es) using the [Fastify](https://github.com/fastify/fastify) server.
10
9
  If you are comfortable with HTTP/1 only and want a compact, ready-to-use setup, this repository is for you.
11
10
 
12
- It simplifies the binding of controllers and middlewares.
13
-
11
+ It simplifies the binding of controllers and middlewares.
14
12
  I use it as a basis for integration into Nestjs, which will be implemented [here](https://github.com/funduck/connectrpc-fastify-nestjs).
15
13
 
16
14
 
@@ -22,6 +20,7 @@ This library allows you to:
22
20
  * Perform RPC with streaming responses
23
21
  * Perform RPC with streaming requests
24
22
  * Use middlewares with Fastify hooks
23
+ * Use interceptors for RPC-level request/response handling
25
24
  * Access HandlerContext in controllers (headers, context values, etc.)
26
25
 
27
26
  *Bidirectional streaming RPC is currently out of scope because it requires HTTP/2, which is unstable on public networks. In practice, HTTP/1 provides more consistent performance.*
@@ -32,7 +31,7 @@ You can check out `test` directory for a complete example of server and client.
32
31
  ### Controllers
33
32
  Controller must implement the service interface and register itself with `ConnectRPC.registerController` in the constructor.
34
33
 
35
- Controller methods receive `HandlerContext` which provides access to request headers, context values, and other metadata.
34
+ Controller methods receive original Connectrpc's `HandlerContext` which provides access to request headers, context values, and other metadata.
36
35
 
37
36
  ```TS
38
37
  import type { HandlerContext } from '@connectrpc/connect';
@@ -75,7 +74,7 @@ try {
75
74
  ```
76
75
 
77
76
  ### Middlewares
78
- Middlewares run as Fastify hooks and have access to raw request/response objects.
77
+ Middlewares run as Fastify hooks and have access to raw request/response objects and context values which can be retrieved using `getCustomContextValues` helper.
79
78
 
80
79
  Middleware must implement `Middleware` interface and register itself with `ConnectRPC.registerMiddleware` in the constructor.
81
80
  ```TS
@@ -97,7 +96,10 @@ export class AuthMiddleware implements Middleware {
97
96
  }
98
97
  ```
99
98
 
100
- Create an instance of the middleware before registering the ConnectRPC plugin.
99
+ Create an instance of the middleware before registering the ConnectRPC plugin.
100
+ And then initialize middlewares using `ConnectRPC.initMiddlewares` method.
101
+ You can configure middleware to run globally for all services and methods, for specific service only, or for specific method only.
102
+ For type safety use `middlewareConfig` helper.
101
103
  ```TS
102
104
  const fastify = Fastify({ logger: true });
103
105
 
@@ -107,13 +109,103 @@ new AuthMiddleware();
107
109
  await ConnectRPC.registerFastifyPlugin(fastify);
108
110
 
109
111
  ConnectRPC.initMiddlewares(fastify, [
110
- middlewareConfig(AuthMiddleware), // Global middleware for all services and methods
111
- // middlewareConfig(AuthMiddleware, ElizaService), // Middleware for all ElizaService methods
112
- // middlewareConfig(AuthMiddleware, ElizaService, ['say']), // Middleware for specific method only
112
+ middlewareConfig(AuthMiddleware), // Global - for all services and methods
113
+ // middlewareConfig(AuthMiddleware, ElizaService), // for all ElizaService methods
114
+ // middlewareConfig(AuthMiddleware, ElizaService, ['say']), // for specific method only
113
115
  ]);
114
116
 
115
117
  await fastify.listen({ port: 3000 });
116
118
  ```
117
119
 
120
+ ### Interceptors
121
+ Interceptors run at the RPC layer and have access to the full request/response context from ConnectRPC. They are executed after middlewares and before the controller method is called.
122
+
123
+ Interceptor must implement `Interceptor` interface and register itself with `ConnectRPC.registerInterceptor` in the constructor.
124
+ ```TS
125
+ import { createContextKey } from '@connectrpc/connect';
126
+ import type { AnyFn, Interceptor } from '@funduck/connectrpc-fastify';
127
+
128
+ const reqIdKey = createContextKey('');
129
+
130
+ export class LoggingInterceptor implements Interceptor {
131
+ constructor() {
132
+ ConnectRPC.registerInterceptor(this);
133
+ }
134
+
135
+ use(next: AnyFn): AnyFn {
136
+ return async (req) => {
137
+ // Access request information
138
+ console.log(`Method: ${req.method.name}`);
139
+ console.log(`Service: ${req.service.typeName}`);
140
+
141
+ // Access headers
142
+ const authHeader = req.header.get('authorization');
143
+
144
+ // Attach custom data to context
145
+ req.contextValues.set(reqIdKey, crypto.randomUUID());
146
+
147
+ // Continue with the request
148
+ return await next(req);
149
+ };
150
+ }
151
+ }
152
+ ```
153
+
154
+ Create an instance of the interceptor and initialize them using `ConnectRPC.init` method.
155
+ You can configure interceptors to run globally for all services and methods, for specific service only, or for specific method only.
156
+ For type safety use `interceptorConfig` helper.
157
+ ```TS
158
+ import { interceptorConfig } from '@funduck/connectrpc-fastify';
159
+
160
+ const fastify = Fastify({ logger: true });
161
+
162
+ new AuthMiddleware();
163
+ new LoggingInterceptor();
164
+ new ElizaController();
165
+
166
+ await ConnectRPC.init(fastify, {
167
+ interceptors: [
168
+ interceptorConfig(LoggingInterceptor), // Global - for all services and methods
169
+ // interceptorConfig(LoggingInterceptor, ElizaService), // for all ElizaService methods
170
+ // interceptorConfig(LoggingInterceptor, ElizaService, ['say']), // for specific method only
171
+ ],
172
+ middlewares: [
173
+ middlewareConfig(AuthMiddleware), // Global middleware
174
+ ],
175
+ });
176
+
177
+ await fastify.listen({ port: 3000 });
178
+ ```
179
+
180
+ **Key differences between Middlewares and Interceptors:**
181
+ - **Middlewares** run at the HTTP layer (Fastify hooks) with access to raw HTTP request/response objects
182
+ - **Interceptors** run at the RPC layer with access to parsed ConnectRPC request/response objects, typed method information, and can modify the request/response in the RPC context
183
+
184
+ ## Using Context Values
185
+ This is original `ContextValues`, so you need to create context keys using `createContextKey` helper from Connectrpc.
186
+ ```TS
187
+ import { createContextKey } from '@connectrpc/connect';
188
+
189
+ const authKey = createContextKey(''); // '' as default value
190
+ ```
191
+
192
+ To use context values in middleware, retrieve them using `getCustomContextValues` helper.
193
+ ```TS
194
+ import { getCustomContextValues } from '@funduck/connectrpc-fastify';
195
+
196
+ // In middleware "use" method
197
+ const authHeader = req.headers['authorization'];
198
+ const contextValues = getCustomContextValues(req);
199
+ contextValues.set(authKey, authHeader);
200
+ ```
201
+
202
+ To use context values in controller, retrieve them from `HandlerContext`.
203
+ ```TS
204
+ // In controller method
205
+ const authValue = context.values.get(authKey);
206
+ ```
207
+
208
+ **Note:** Context values set in middlewares are automatically available in interceptors and controllers. Interceptors can also access and modify context values using `req.contextValues`.
209
+
118
210
  ## Feedback
119
211
  Please use [Discussions](https://github.com/funduck/connectrpc-fastify/discussions) or email me.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funduck/connectrpc-fastify",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "author": "Oleg Milekhin <qlfunduck@gmail.com>",
5
5
  "description": "Wrapper for official @connectrpc/connect and fastify. Simplifies configuration, type safe binding to controller, simplifies use of middlewares and guards.",
6
6
  "main": "dist/index.js",
@@ -32,6 +32,7 @@
32
32
  "prettier-plugin-organize-imports": "^4.3.0",
33
33
  "ts-jest": "^29.4.6",
34
34
  "ts-node": "^10.9.2",
35
- "typescript": "^5.9.3"
35
+ "typescript": "^5.9.3",
36
+ "reflect-metadata": "^0.2.2"
36
37
  }
37
38
  }