@rexeus/typeweaver-types 0.0.2 โ 0.0.4
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.
- package/README.md +153 -419
- package/dist/LICENSE +202 -0
- package/dist/NOTICE +4 -0
- package/dist/index.js +169 -2156
- package/dist/lib/RequestValidator.ts +13 -2
- package/dist/lib/ResponseValidator.ts +82 -1
- package/dist/lib/Validator.ts +207 -0
- package/dist/lib/assert.ts +7 -0
- package/dist/lib/index.ts +8 -1
- package/dist/templates/Request.ejs +12 -53
- package/dist/templates/RequestValidator.ejs +12 -2
- package/dist/templates/Response.ejs +8 -0
- package/dist/templates/ResponseValidator.ejs +35 -81
- package/dist/templates/SharedResponse.ejs +8 -0
- package/package.json +15 -10
- package/dist/lib/InvalidResponseStatusCodeError.ts +0 -21
package/README.md
CHANGED
|
@@ -1,483 +1,217 @@
|
|
|
1
|
-
# @rexeus/typeweaver-types
|
|
1
|
+
# ๐งตโจ @rexeus/typeweaver-types
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@rexeus/typeweaver-types)
|
|
4
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Typeweaver is a type-safe HTTP API framework built for API-first development with a focus on
|
|
8
|
+
developer experience. Use typeweaver to specify your HTTP APIs in TypeScript and Zod, and generate
|
|
9
|
+
clients, validators, routers, and more โจ
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
providing the foundation for type-safe API development. This is the core plugin that's included by
|
|
9
|
-
default in TypeWeaver.
|
|
11
|
+
## ๐ Types Plugin
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
This plugin generates TypeScript types and Zod validators from your typeweaver API definitions,
|
|
14
|
+
providing the foundation for type-safe API development. This is the core plugin that's included by
|
|
15
|
+
default in every typeweaver generation.
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
npm install @rexeus/typeweaver-types
|
|
15
|
-
```
|
|
17
|
+
---
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
## ๐ฅ Installation
|
|
18
20
|
|
|
19
21
|
```bash
|
|
20
|
-
|
|
22
|
+
# Install the CLI as a dev dependency
|
|
23
|
+
# Types plugin will be automatically included
|
|
24
|
+
npm install -D @rexeus/typeweaver
|
|
25
|
+
|
|
26
|
+
# Install the runtime as a dependency
|
|
27
|
+
npm install @rexeus/typeweaver-core
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
##
|
|
30
|
+
## ๐ก How to use
|
|
24
31
|
|
|
25
32
|
This plugin is included by default and doesn't need to be explicitly specified:
|
|
26
33
|
|
|
27
34
|
```bash
|
|
28
|
-
|
|
35
|
+
# Generate with clients + types plugins
|
|
36
|
+
npx typeweaver generate --input ./api/definition --output ./api/generated --plugins clients
|
|
29
37
|
```
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
More details on how to use the [CLI](https://github.com/rexeus/typeweaver/tree/main/packages/cli/README.md#๏ธ-cli).
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
npx typeweaver generate --input ./api/definitions --output ./api/generated --plugins types,clients,aws-cdk
|
|
35
|
-
```
|
|
41
|
+
## ๐ Generated Output
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
For each operation (e.g., `CreateTodo`), the plugin generates four main files:
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
- `<OperationId>Request.ts`
|
|
46
|
+
- `<OperationId>Response.ts`
|
|
47
|
+
- `<OperationId>RequestValidator.ts`
|
|
48
|
+
- `<OperationId>ResponseValidator.ts`
|
|
40
49
|
|
|
41
|
-
|
|
50
|
+
These files contain the necessary types and validators for requests and responses. All of these
|
|
51
|
+
provided types and classes are exported.
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
### ๐จ Request Types
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
3. **Request Validators** (`GetUserRequestValidator.ts`)
|
|
48
|
-
4. **Response Validators** (`GetUserResponseValidator.ts`)
|
|
55
|
+
All request-related types for an operation are defined in one file: `<OperationId>Request.ts`, e.g.
|
|
56
|
+
`CreateTodoRequest.ts`. This file contains:
|
|
49
57
|
|
|
50
|
-
|
|
58
|
+
- **`I<OperationId>RequestHeader`** - Type of request headers, if defined, e.g.
|
|
59
|
+
`ICreateTodoRequestHeader`
|
|
60
|
+
- **`I<OperationId>RequestPath`** - Type for path parameters, if defined, e.g.
|
|
61
|
+
`ICreateTodoRequestPath`
|
|
62
|
+
- **`I<OperationId>RequestQuery`** - Type for query parameters, if defined, e.g.
|
|
63
|
+
`ICreateTodoRequestQuery`
|
|
64
|
+
- **`I<OperationId>RequestBody`** - Type for request body, if defined, e.g. `ICreateTodoRequestBody`
|
|
65
|
+
- **`I<OperationId>Request`** - Complete request interface combining path, method, headers, and
|
|
66
|
+
body, e.g. `ICreateTodoRequest`
|
|
67
|
+
- **`Successful<OperationId>Response`** - Union type excluding error responses for success-only
|
|
68
|
+
handling
|
|
51
69
|
|
|
52
|
-
|
|
70
|
+
### ๐ฌ Response Types
|
|
53
71
|
|
|
54
|
-
-
|
|
72
|
+
All response-related types for an operation are defined in one file: `<OperationId>Response.ts`,
|
|
73
|
+
e.g. `CreateTodoResponse.ts`. This file contains for each response defined inline in an operation:
|
|
55
74
|
|
|
56
|
-
|
|
75
|
+
- **`I<ResponseName>ResponseHeader`** - Type for success response headers, if defined, e.g.
|
|
76
|
+
`ICreateTodoSuccessResponseHeader`
|
|
77
|
+
- **`I<ResponseName>ResponseBody`** - Type for success response payload structure, if defined, e.g.
|
|
78
|
+
`ICreateTodoSuccessResponseBody`
|
|
79
|
+
- **`I<ResponseName>Response`** - Complete success response interface with status code, e.g.
|
|
80
|
+
`I<ResponseName>Response`
|
|
81
|
+
- **`<ResponseName>Response`** - Response class extending HttpResponse with validation and type
|
|
82
|
+
safety, e.g. `CreateTodoSuccessResponse`
|
|
57
83
|
|
|
58
|
-
|
|
84
|
+
Furthermore, two union types are generated, which include details about all possible responses
|
|
85
|
+
(success + error), not only those defined inline in the operation:
|
|
59
86
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
import { HttpRequest } from "@rexeus/typeweaver-core";
|
|
63
|
-
import { z } from "zod/v4";
|
|
64
|
-
|
|
65
|
-
export const GetUserRequestSchema = z.object({
|
|
66
|
-
param: z.object({
|
|
67
|
-
userId: z.string().uuid(),
|
|
68
|
-
}),
|
|
69
|
-
header: z
|
|
70
|
-
.object({
|
|
71
|
-
Authorization: z.string(),
|
|
72
|
-
Accept: z.literal("application/json"),
|
|
73
|
-
})
|
|
74
|
-
.optional(),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
export type GetUserRequest = z.infer<typeof GetUserRequestSchema>;
|
|
78
|
-
|
|
79
|
-
export interface IGetUserRequest extends HttpRequest {
|
|
80
|
-
param: {
|
|
81
|
-
userId: string;
|
|
82
|
-
};
|
|
83
|
-
header?: {
|
|
84
|
-
Authorization: string;
|
|
85
|
-
Accept: "application/json";
|
|
86
|
-
};
|
|
87
|
-
}
|
|
87
|
+
- **`I<OperationId>Response`** - Union type of all response types e.g. `ICreateTodoResponse`
|
|
88
|
+
- **`<OperationId>Response`** - Union type of all response classes, e.g. `CreateTodoResponse`
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
constructor(public readonly data: IGetUserRequest) {
|
|
91
|
-
GetUserRequestSchema.parse(data);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
90
|
+
### ๐จโ Request Validators
|
|
95
91
|
|
|
96
|
-
|
|
92
|
+
Request validation logic for an operation is defined in one file:
|
|
93
|
+
`<OperationId>RequestValidator.ts`, e.g. `CreateTodoRequestValidator.ts`. This file contains:
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
name: z.string(),
|
|
112
|
-
email: z.string().email(),
|
|
113
|
-
}),
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
export type GetUserSuccessResponse = z.infer<typeof GetUserSuccessResponseSchema>;
|
|
117
|
-
|
|
118
|
-
// Error Responses
|
|
119
|
-
export type GetUserErrorResponse =
|
|
120
|
-
| UserNotFoundErrorResponse
|
|
121
|
-
| ValidationErrorResponse
|
|
122
|
-
| InternalServerErrorResponse;
|
|
123
|
-
|
|
124
|
-
// Union Type
|
|
125
|
-
export type GetUserResponse = GetUserSuccessResponse | GetUserErrorResponse;
|
|
126
|
-
|
|
127
|
-
export interface IGetUserResponse extends HttpResponse {
|
|
128
|
-
statusCode: 200 | 404 | 400 | 500;
|
|
129
|
-
header: {
|
|
130
|
-
"Content-Type": "application/json";
|
|
131
|
-
};
|
|
132
|
-
body:
|
|
133
|
-
| {
|
|
134
|
-
id: string;
|
|
135
|
-
name: string;
|
|
136
|
-
email: string;
|
|
137
|
-
}
|
|
138
|
-
| {
|
|
139
|
-
message: string;
|
|
140
|
-
code: string;
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
```
|
|
95
|
+
- **`<OperationId>RequestValidator`** - Main validation class extending `RequestValidator`, e.g.
|
|
96
|
+
`CreateTodoRequestValidator`
|
|
97
|
+
- **`safeValidate()`** - Non-throwing validation method returning `SafeRequestValidationResult`
|
|
98
|
+
- **`validate()`** - Throwing validation method that returns validated request or throws
|
|
99
|
+
`RequestValidationError`
|
|
100
|
+
- **Header coercion logic** - Automatic conversion of headers to schema-appropriate types (single
|
|
101
|
+
string value & multi string value headers)
|
|
102
|
+
- **Query parameter coercion logic** - Automatic conversion of query parameters to
|
|
103
|
+
schema-appropriate types (single string value & multi string value query parameters)
|
|
104
|
+
- **Request validation errors** - Includes all issues related to the incoming request for headers,
|
|
105
|
+
query parameters, and body.
|
|
106
|
+
- **Unknown property filtering** - Automatically removes properties not defined in the request
|
|
107
|
+
schema. If a request exceeds the definition, it is not rejected directly.
|
|
144
108
|
|
|
145
|
-
|
|
109
|
+
**Using the generated request validators**
|
|
146
110
|
|
|
147
111
|
```typescript
|
|
148
|
-
|
|
149
|
-
import {
|
|
150
|
-
import { GetUserRequestSchema } from "./GetUserRequest";
|
|
151
|
-
|
|
152
|
-
export class GetUserRequestValidator extends RequestValidator<typeof GetUserRequestSchema> {
|
|
153
|
-
constructor() {
|
|
154
|
-
super(GetUserRequestSchema);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
public validate(request: unknown): GetUserRequest {
|
|
158
|
-
return this.schema.parse(request);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
public safeValidate(request: unknown): SafeParseResult<GetUserRequest> {
|
|
162
|
-
return this.schema.safeParse(request);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Response Validators
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
// GetUserResponseValidator.ts
|
|
171
|
-
import { ResponseValidator } from "@rexeus/typeweaver-core";
|
|
172
|
-
import { GetUserResponse } from "./GetUserResponse";
|
|
173
|
-
|
|
174
|
-
export class GetUserResponseValidator extends ResponseValidator {
|
|
175
|
-
public validate(response: unknown): GetUserResponse {
|
|
176
|
-
const statusCode = (response as any)?.statusCode;
|
|
177
|
-
|
|
178
|
-
switch (statusCode) {
|
|
179
|
-
case 200:
|
|
180
|
-
return this.validateSuccessResponse(response);
|
|
181
|
-
case 404:
|
|
182
|
-
return this.validateUserNotFoundError(response);
|
|
183
|
-
case 400:
|
|
184
|
-
return this.validateValidationError(response);
|
|
185
|
-
case 500:
|
|
186
|
-
return this.validateInternalServerError(response);
|
|
187
|
-
default:
|
|
188
|
-
throw new ResponseValidationError(`Unexpected status code: ${statusCode}`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
112
|
+
import { RequestValidationError, type IHttpRequest } from "@rexeus/typeweaver-core";
|
|
113
|
+
import { CreateTodoRequestValidator } from "path/to/generated/output";
|
|
191
114
|
|
|
192
|
-
|
|
193
|
-
return GetUserSuccessResponseSchema.parse(response);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// ... other validation methods
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Type Features
|
|
201
|
-
|
|
202
|
-
### Complete Type Safety
|
|
203
|
-
|
|
204
|
-
- **Request Types** - Fully typed request interfaces
|
|
205
|
-
- **Response Types** - Union types for all possible responses
|
|
206
|
-
- **Parameter Types** - Path, query, header, and body parameters
|
|
207
|
-
- **Validation Types** - Runtime validation with Zod schemas
|
|
115
|
+
const requestValidator = new CreateTodoRequestValidator();
|
|
208
116
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- **Runtime Validation** - Type-safe validation at runtime
|
|
213
|
-
- **Error Handling** - Structured validation errors
|
|
214
|
-
- **Type Inference** - TypeScript types inferred from Zod schemas
|
|
215
|
-
|
|
216
|
-
### Error Response Handling
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
// Shared error responses are reused across operations
|
|
220
|
-
export type UserNotFoundErrorResponse = {
|
|
221
|
-
statusCode: 404;
|
|
222
|
-
body: {
|
|
223
|
-
message: "User not found";
|
|
224
|
-
code: "USER_NOT_FOUND";
|
|
225
|
-
userId: string;
|
|
226
|
-
};
|
|
117
|
+
// A request in structure of IHttpRequest
|
|
118
|
+
const request: IHttpRequest = {
|
|
119
|
+
// ...
|
|
227
120
|
};
|
|
228
121
|
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
## Usage Examples
|
|
237
|
-
|
|
238
|
-
### Request Validation
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
import { GetUserRequestValidator } from "./api/generated";
|
|
242
|
-
|
|
243
|
-
const validator = new GetUserRequestValidator();
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
const validatedRequest = validator.validate({
|
|
247
|
-
param: { userId: "123e4567-e89b-12d3-a456-426614174000" },
|
|
248
|
-
header: { Authorization: "Bearer token" },
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// validatedRequest is fully typed
|
|
252
|
-
console.log(validatedRequest.param.userId);
|
|
253
|
-
} catch (error) {
|
|
254
|
-
console.error("Validation failed:", error.issues);
|
|
122
|
+
// Using safe validation
|
|
123
|
+
const safeResult = requestValidator.safeValidate(request);
|
|
124
|
+
if (safeResult.isValid) {
|
|
125
|
+
console.log("Request is valid", safeResult.data);
|
|
126
|
+
} else {
|
|
127
|
+
// Error is instance of RequestValidationError class
|
|
128
|
+
console.log("Request is invalid", safeResult.error);
|
|
255
129
|
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Response Validation
|
|
259
|
-
|
|
260
|
-
```typescript
|
|
261
|
-
import { GetUserResponseValidator } from "./api/generated";
|
|
262
|
-
|
|
263
|
-
const validator = new GetUserResponseValidator();
|
|
264
130
|
|
|
131
|
+
// Using throwing validation
|
|
265
132
|
try {
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
header: { "Content-Type": "application/json" },
|
|
269
|
-
body: { id: "123", name: "John", email: "john@example.com" },
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// Response is typed based on status code
|
|
273
|
-
if (validatedResponse.statusCode === 200) {
|
|
274
|
-
console.log(validatedResponse.body.name); // Type-safe access
|
|
275
|
-
}
|
|
133
|
+
const validatedRequest = requestValidator.validate(request);
|
|
134
|
+
console.log("Request is valid", validatedRequest);
|
|
276
135
|
} catch (error) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### Type Guards
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
import { GetUserResponse } from "./api/generated";
|
|
285
|
-
|
|
286
|
-
function isSuccessResponse(response: GetUserResponse): response is GetUserSuccessResponse {
|
|
287
|
-
return response.statusCode === 200;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function handleResponse(response: GetUserResponse) {
|
|
291
|
-
if (isSuccessResponse(response)) {
|
|
292
|
-
// TypeScript knows this is a success response
|
|
293
|
-
console.log(response.body.name);
|
|
294
|
-
} else {
|
|
295
|
-
// TypeScript knows this is an error response
|
|
296
|
-
console.error(response.body.message);
|
|
136
|
+
if (error instanceof RequestValidationError) {
|
|
137
|
+
console.log("Request is invalid", error);
|
|
297
138
|
}
|
|
298
139
|
}
|
|
299
140
|
```
|
|
300
141
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
### With Clients Plugin
|
|
142
|
+
### ๐ฌโ Response Validators
|
|
304
143
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
// Generated by types plugin
|
|
309
|
-
import { GetUserRequestCommand, GetUserResponse } from "./GetUserRequest";
|
|
310
|
-
import { GetUserResponseValidator } from "./GetUserResponseValidator";
|
|
311
|
-
|
|
312
|
-
// Used by clients plugin
|
|
313
|
-
export class UsersClient {
|
|
314
|
-
async send(command: GetUserRequestCommand): Promise<GetUserResponse> {
|
|
315
|
-
const response = await this.makeRequest(command);
|
|
316
|
-
const validator = new GetUserResponseValidator();
|
|
317
|
-
return validator.validate(response);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
```
|
|
144
|
+
Response validation logic for an operation is defined in one file:
|
|
145
|
+
`<OperationId>ResponseValidator.ts`, e.g. `CreateTodoResponseValidator.ts`. This file contains:
|
|
321
146
|
|
|
322
|
-
|
|
147
|
+
- **`<OperationId>ResponseValidator`** - Main validation class extending `ResponseValidator`, e.g.
|
|
148
|
+
`CreateTodoResponseValidator`
|
|
149
|
+
- **`safeValidate()`** - Non-throwing validation method returning `SafeResponseValidationResult`
|
|
150
|
+
- **`validate()`** - Throwing validation method that returns validated response or throws
|
|
151
|
+
ResponseValidationError
|
|
152
|
+
- Valid response data is an instance of one of the generated response classes
|
|
153
|
+
- **Header coercion logic** - Automatic conversion of headers to schema-appropriate types (single
|
|
154
|
+
string value & multi string value headers)
|
|
155
|
+
- **Response validation errors** - Include details about the issues with all possible responses for
|
|
156
|
+
the given status code:
|
|
157
|
+
- An issue for a possible response includes details about header and body issues
|
|
158
|
+
- If the given status code is not specified in the operation at all an issue with details about
|
|
159
|
+
expected status codes is included
|
|
160
|
+
- **Unknown property filtering** - Automatically removes properties not defined in the response
|
|
161
|
+
schema. If a response exceeds the definition, it is not rejected directly.
|
|
323
162
|
|
|
324
|
-
|
|
163
|
+
**Using the generated response validators**
|
|
325
164
|
|
|
326
165
|
```typescript
|
|
327
|
-
|
|
328
|
-
import {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// Handle request with type safety
|
|
340
|
-
const user = await userService.getUser(validatedRequest.param.userId);
|
|
341
|
-
|
|
342
|
-
return {
|
|
343
|
-
statusCode: 200,
|
|
344
|
-
body: JSON.stringify(user),
|
|
345
|
-
};
|
|
346
|
-
} catch (error) {
|
|
347
|
-
if (error instanceof ValidationError) {
|
|
348
|
-
return {
|
|
349
|
-
statusCode: 400,
|
|
350
|
-
body: JSON.stringify({ message: "Invalid request", issues: error.issues }),
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
throw error;
|
|
354
|
-
}
|
|
166
|
+
import { ResponseValidationError, type IHttpResponse } from "@rexeus/typeweaver-core";
|
|
167
|
+
import {
|
|
168
|
+
CreateTodoResponseValidator,
|
|
169
|
+
CreateTodoSuccessResponse,
|
|
170
|
+
InternalServerErrorResponse,
|
|
171
|
+
} from "path/to/generated/output";
|
|
172
|
+
|
|
173
|
+
const responseValidator = new CreateTodoResponseValidator();
|
|
174
|
+
|
|
175
|
+
// A response in structure of IHttpResponse
|
|
176
|
+
const response: IHttpResponse = {
|
|
177
|
+
// ...
|
|
355
178
|
};
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## Advanced Features
|
|
359
|
-
|
|
360
|
-
### Custom Validators
|
|
361
|
-
|
|
362
|
-
Extend generated validators for custom validation logic:
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
import { GetUserRequestValidator } from "./api/generated";
|
|
366
179
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
180
|
+
// Using safe validation
|
|
181
|
+
const safeResult = responseValidator.safeValidate(response);
|
|
182
|
+
if (safeResult.isValid) {
|
|
183
|
+
console.log("Response is valid", safeResult.data);
|
|
370
184
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return validated;
|
|
185
|
+
// Data is an instance of one of the defined response classes
|
|
186
|
+
if (safeResult.data instanceof CreateTodoSuccessResponse) {
|
|
187
|
+
// handle CreateTodoSuccessResponse
|
|
377
188
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
### Schema Composition
|
|
382
|
-
|
|
383
|
-
Generated schemas can be composed and extended:
|
|
384
|
-
|
|
385
|
-
```typescript
|
|
386
|
-
import { GetUserRequestSchema } from "./api/generated";
|
|
387
|
-
|
|
388
|
-
// Extend for internal usage
|
|
389
|
-
export const InternalGetUserRequestSchema = GetUserRequestSchema.extend({
|
|
390
|
-
internal: z.object({
|
|
391
|
-
requestId: z.string(),
|
|
392
|
-
userId: z.string(),
|
|
393
|
-
}),
|
|
394
|
-
});
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
## Plugin Architecture
|
|
398
|
-
|
|
399
|
-
This plugin extends the TypeWeaver plugin system:
|
|
400
|
-
|
|
401
|
-
```typescript
|
|
402
|
-
import { BasePlugin, type GeneratorContext } from "@rexeus/typeweaver-gen";
|
|
403
|
-
|
|
404
|
-
export default class TypesPlugin extends BasePlugin {
|
|
405
|
-
public name = "types";
|
|
406
|
-
|
|
407
|
-
public override generate(context: GeneratorContext): void {
|
|
408
|
-
// Generates types and validators for all operations
|
|
409
|
-
SharedResponseGenerator.generate(context);
|
|
410
|
-
RequestGenerator.generate(context);
|
|
411
|
-
RequestValidationGenerator.generate(context);
|
|
412
|
-
ResponseGenerator.generate(context);
|
|
413
|
-
ResponseValidationGenerator.generate(context);
|
|
189
|
+
if (safeResult.data instanceof InternalServerErrorResponse) {
|
|
190
|
+
// handle InternalServerErrorResponse
|
|
414
191
|
}
|
|
192
|
+
// handle other response types ...
|
|
193
|
+
} else {
|
|
194
|
+
// Error is instance of ResponseValidationError class
|
|
195
|
+
console.log("Response is invalid", safeResult.error);
|
|
415
196
|
}
|
|
416
|
-
```
|
|
417
197
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
- Keep generated types in source control for review
|
|
423
|
-
- Regenerate types when API definitions change
|
|
424
|
-
- Use TypeScript strict mode for maximum safety
|
|
425
|
-
|
|
426
|
-
### Validation Strategy
|
|
198
|
+
// Using throwing validation
|
|
199
|
+
try {
|
|
200
|
+
const validatedResponse = responseValidator.validate(response);
|
|
201
|
+
console.log("Response is valid", validatedResponse);
|
|
427
202
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// Business logic with typed data
|
|
437
|
-
const user = await this.userService.getUser(validatedRequest.param.userId);
|
|
438
|
-
|
|
439
|
-
// Return typed response
|
|
440
|
-
return {
|
|
441
|
-
statusCode: 200,
|
|
442
|
-
body: user,
|
|
443
|
-
} as GetUserSuccessResponse;
|
|
203
|
+
// Same here: Data is an instance of one of the defined response classes
|
|
204
|
+
if (validatedResponse instanceof CreateTodoSuccessResponse) {
|
|
205
|
+
// handle CreateTodoSuccessResponse
|
|
206
|
+
}
|
|
207
|
+
// ... handle other response types
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (error instanceof ResponseValidationError) {
|
|
210
|
+
console.log("Response is invalid", error);
|
|
444
211
|
}
|
|
445
212
|
}
|
|
446
213
|
```
|
|
447
214
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
```typescript
|
|
451
|
-
// Centralized error mapping
|
|
452
|
-
export function mapValidationError(error: ZodError): ValidationErrorResponse {
|
|
453
|
-
return {
|
|
454
|
-
statusCode: 400,
|
|
455
|
-
body: {
|
|
456
|
-
message: "Validation failed",
|
|
457
|
-
issues: error.issues.map(issue => ({
|
|
458
|
-
path: issue.path.join("."),
|
|
459
|
-
message: issue.message,
|
|
460
|
-
})),
|
|
461
|
-
},
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
## Troubleshooting
|
|
467
|
-
|
|
468
|
-
### Common Issues
|
|
469
|
-
|
|
470
|
-
**Type conflicts**: Ensure API definitions are consistent **Validation errors**: Check Zod schema
|
|
471
|
-
compatibility **Import issues**: Verify generated files are properly exported
|
|
472
|
-
|
|
473
|
-
### Debug Mode
|
|
474
|
-
|
|
475
|
-
Enable detailed generation logging:
|
|
476
|
-
|
|
477
|
-
```bash
|
|
478
|
-
DEBUG=typeweaver:types npx typeweaver generate --plugins types
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
## License
|
|
215
|
+
## ๐ License
|
|
482
216
|
|
|
483
|
-
|
|
217
|
+
Apache 2.0 ยฉ Dennis Wentzien 2025
|