Skip to content

Commit d211cb4

Browse files
authored
Merge pull request #157 from bufferings/work
Fix documentation errors and improve code examples
2 parents e9aeadd + b09cca3 commit d211cb4

25 files changed

+300
-126
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ app.get('/greeting', (ctx) => {
5555

5656
// With path parameter
5757
app.get('/greeting/:name', (ctx) => {
58-
const { name } = ctx.req.pathParams();
58+
const { name } = ctx.req.params();
5959
return ctx.res.json({ message: `Hello, ${name}!` });
6060
});
6161
```
@@ -308,6 +308,7 @@ Now you can visit http://localhost:3000/docs for interactive API documentation.
308308
- [`@korix/kori`](./packages/kori) - Core framework
309309
- [`@korix/nodejs-server`](./packages/nodejs-server) - Node.js HTTP server adapter
310310
- [`@korix/zod-schema-adapter`](./packages/zod-schema-adapter) - Zod schema adapter for request and response validation
311+
- [`@korix/standard-schema-adapter`](./packages/standard-schema-adapter) - Standard Schema adapter for validation with other schema libraries
311312
- [`@korix/zod-openapi-plugin`](./packages/zod-openapi-plugin) - OpenAPI document generation from Zod schemas
312313
- [`@korix/openapi-swagger-ui-plugin`](./packages/openapi-swagger-ui-plugin) - Interactive API documentation with Swagger UI
313314

docs/en/guide/getting-started.md

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,46 @@ Your API is running at `http://localhost:3000`
1414

1515
## Basic API
1616

17-
Create your first endpoint:
17+
Create your first endpoint and run it:
1818

1919
```typescript
2020
import { createKori } from '@korix/kori';
21+
import { startNodejsServer } from '@korix/nodejs-server';
2122

2223
const app = createKori();
2324

2425
app.get('/hello', (ctx) => {
2526
return ctx.res.text('Hello, Kori!');
2627
});
2728

28-
export { app };
29+
await startNodejsServer(app, { port: 3000 });
30+
```
31+
32+
Your API is now running at `http://localhost:3000/hello`
33+
34+
## Running the Server
35+
36+
### Node.js Server
37+
38+
The example above uses the Node.js server adapter. You can also configure hostname and other options:
39+
40+
```typescript
41+
await startNodejsServer(app, {
42+
port: 3000,
43+
hostname: 'localhost',
44+
});
45+
```
46+
47+
### Testing & Custom Environments
48+
49+
For testing or custom deployments, you can use the `.start()` method to initialize the application and get a fetch handler:
50+
51+
```typescript
52+
// Initialize the application
53+
const { fetchHandler } = await app.start();
54+
55+
// Use the fetch handler directly (e.g., in tests)
56+
const response = await fetchHandler(new Request('http://localhost/hello'));
2957
```
3058

3159
## Request & Response
@@ -81,8 +109,8 @@ app.log().info('Application will start');
81109
export { app };
82110
```
83111

84-
- **`app.log()`** - Application-level logger (outside of Kori context)
85-
- **`ctx.log()`** - Context-aware logger (inside Kori context: hooks and handlers)
112+
- `app.log()` - Application-level logger (outside of Kori context)
113+
- `ctx.log()` - Context-aware logger (inside Kori context: hooks and handlers)
86114

87115
Sample log output:
88116

@@ -206,9 +234,11 @@ Generate interactive API documentation from your validation schemas:
206234

207235
```typescript
208236
import { createKori } from '@korix/kori';
237+
import { startNodejsServer } from '@korix/nodejs-server';
209238
import {
210239
zodRequestSchema,
211-
enableZodRequestValidation,
240+
zodResponseSchema,
241+
enableZodRequestAndResponseValidation,
212242
} from '@korix/zod-schema-adapter';
213243
import { zodOpenApiPlugin } from '@korix/zod-openapi-plugin';
214244
import { swaggerUiPlugin } from '@korix/openapi-swagger-ui-plugin';
@@ -219,27 +249,29 @@ const CreateUserSchema = z.object({
219249
age: z.number().int().min(0).optional(),
220250
});
221251

252+
const UserResponseSchema = z.object({
253+
id: z.string(),
254+
name: z.string(),
255+
age: z.number().optional(),
256+
createdAt: z.string(),
257+
});
258+
222259
const app = createKori({
223-
...enableZodRequestValidation(),
260+
...enableZodRequestAndResponseValidation(),
224261
})
225-
// Generate OpenAPI specification from Zod schemas
226262
.applyPlugin(
227263
zodOpenApiPlugin({
228264
info: { title: 'My API', version: '1.0.0' },
229265
}),
230266
)
231-
// Serve interactive documentation UI
232267
.applyPlugin(swaggerUiPlugin());
233268

234269
app.post('/users', {
235270
requestSchema: zodRequestSchema({ body: CreateUserSchema }),
236-
responseSchema: zodResponseSchema({ default: z.any() }),
271+
responseSchema: zodResponseSchema({ '201': UserResponseSchema }),
237272
handler: (ctx) => {
238-
// Type-safe validated body access
239273
const { name, age } = ctx.req.validatedBody();
240274

241-
// Your business logic here (save to database, etc.)
242-
243275
return ctx.res.status(201).json({
244276
id: '42',
245277
name,
@@ -249,7 +281,7 @@ app.post('/users', {
249281
},
250282
});
251283

252-
export { app };
284+
await startNodejsServer(app, { port: 3000 });
253285
```
254286

255287
Visit `http://localhost:3000/docs` for interactive documentation!

docs/en/guide/handler-context.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Handler Context
22

3-
The **Handler Context** manages request processing - accessing request data, building responses, and extending functionality per request. It's passed to every route handler and contains everything you need to process HTTP requests.
3+
The Handler Context manages request processing - accessing request data, building responses, and extending functionality per request. It's passed to every route handler and contains everything you need to process HTTP requests.
44

55
## What is Handler Context?
66

7-
The **KoriHandlerContext** is passed to every route handler and gives you access to request data, response builders, and the application environment:
7+
The KoriHandlerContext is passed to every route handler and gives you access to request data, response builders, and the application environment:
88

99
```typescript
1010
type KoriHandlerContext<Env, Req, Res> = {
@@ -23,14 +23,7 @@ type KoriHandlerContext<Env, Req, Res> = {
2323
};
2424
```
2525

26-
**Used for:**
27-
28-
- Processing HTTP requests
29-
- Accessing request data
30-
- Building responses
31-
- Per-request logic
32-
33-
Handler context supports request and response extensions for adding custom functionality.
26+
Use it for processing HTTP requests, accessing request data, building responses, and per-request logic. Handler context supports request and response extensions for adding custom functionality.
3427

3528
## Basic Usage
3629

@@ -91,6 +84,13 @@ app.get('/users/:id/posts', async (ctx) => {
9184
const textData = await ctx.req.bodyText();
9285
const formData = await ctx.req.bodyFormData();
9386

87+
// Validated data (when using requestSchema)
88+
// const { ... } = ctx.req.validatedParams();
89+
// const { ... } = ctx.req.validatedQueries();
90+
// const { ... } = ctx.req.validatedHeaders();
91+
// const { ... } = ctx.req.validatedCookies();
92+
// const { ... } = ctx.req.validatedBody();
93+
9494
return ctx.res.json({
9595
userId: id,
9696
query: { limit, offset },

docs/en/guide/hook-execution.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Request hooks execute for every matching request.
5050

5151
Key behaviors:
5252

53-
- `defer` callbacks execute in **reverse order** (LIFO)
53+
- `defer` callbacks execute in reverse order (LIFO)
5454
- `onRequest` can stop processing by returning a response
5555
- Hooks are captured when you define routes, not when requests arrive
5656

@@ -127,8 +127,8 @@ app.get('/protected', (ctx) => {
127127

128128
When an error occurs, `onError` hooks replace the normal execution flow:
129129

130-
**Normal flow**: `onRequest` → Route Handler → `defer` callbacks
131-
**Error flow**: `onRequest` → Error occurs → `onError` hooks → `defer` callbacks
130+
- Normal flow: `onRequest` → Route Handler → `defer` callbacks
131+
- Error flow: `onRequest` → Error occurs → `onError` hooks → `defer` callbacks
132132

133133
```typescript
134134
const app = createKori()

docs/en/guide/instance-context.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Instance Context
22

3-
The **Instance Context** manages your application's lifecycle - initialization, configuration, and shutdown. It's where you set up shared resources and configure your application environment.
3+
The Instance Context manages your application's lifecycle - initialization, configuration, and shutdown. It's where you set up shared resources and configure your application environment.
44

55
## What is Instance Context?
66

7-
The **KoriInstanceContext** handles application-wide concerns that happen once when your app starts up or shuts down:
7+
The KoriInstanceContext handles application-wide concerns that happen once when your app starts up or shuts down:
88

99
```typescript
1010
type KoriInstanceContext<Env extends KoriEnvironment> = {
@@ -20,11 +20,7 @@ type KoriInstanceContext<Env extends KoriEnvironment> = {
2020
};
2121
```
2222

23-
**Used for:**
24-
25-
- Setting up database connections
26-
- Loading configuration
27-
- Initializing shared services
23+
Use it for setting up database connections, loading configuration, and initializing shared services.
2824

2925
## Context Extensions
3026

docs/en/guide/openapi.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { zodOpenApiPlugin, openApiMeta } from '@korix/zod-openapi-plugin';
2020
import { swaggerUiPlugin } from '@korix/openapi-swagger-ui-plugin';
2121
import {
2222
zodRequestSchema,
23+
zodResponseSchema,
2324
enableZodRequestValidation,
2425
} from '@korix/zod-schema-adapter';
2526

@@ -66,6 +67,11 @@ const UserSchema = z.object({
6667
}),
6768
});
6869

70+
const UserResponseSchema = z.object({
71+
user: UserSchema,
72+
message: z.string(),
73+
});
74+
6975
// Add to your route
7076
app.post('/users', {
7177
pluginMeta: openApiMeta({
@@ -77,7 +83,7 @@ app.post('/users', {
7783
body: UserSchema,
7884
}),
7985
responseSchema: zodResponseSchema({
80-
default: z.any(),
86+
'201': UserResponseSchema,
8187
}),
8288
handler: (ctx) => {
8389
const user = ctx.req.validatedBody();
@@ -130,7 +136,11 @@ app.get('/products/:id', {
130136
}),
131137
}),
132138
responseSchema: zodResponseSchema({
133-
default: z.any(),
139+
'200': z.object({
140+
id: z.number(),
141+
name: z.string(),
142+
price: z.number(),
143+
}),
134144
}),
135145
handler: (ctx) => {
136146
const { id } = ctx.req.validatedParams();
@@ -366,9 +376,9 @@ app.post('/users', {
366376
email: z.string(),
367377
}),
368378
}),
369-
handler: (ctx) => {
379+
handler: async (ctx) => {
370380
// Handle request without automatic validation
371-
const body = ctx.req.bodyJson(); // Returns unknown, not validated
381+
const body = await ctx.req.bodyJson(); // Returns unknown, not validated
372382

373383
// Your custom validation logic here
374384

docs/en/guide/plugins.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,10 @@ export function authPlugin<
308308

309309
Plugin-specific loggers provide several advantages:
310310

311-
- **Namespace isolation**: Logs are automatically prefixed with `plugin.{pluginName}`
312-
- **Better debugging**: Easy to filter logs by specific plugins
313-
- **Consistent formatting**: Inherits all bindings from the base logger
314-
- **Channel separation**: Plugin logs use dedicated channels for organization
311+
- Namespace isolation: Logs are automatically prefixed with `plugin.{pluginName}`
312+
- Better debugging: Easy to filter logs by specific plugins
313+
- Consistent formatting: Inherits all bindings from the base logger
314+
- Channel separation: Plugin logs use dedicated channels for organization
315315

316316
### Logger Output
317317

docs/en/guide/request-validation.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ app.put('/users/:id', {
7979
headers: z.object({
8080
authorization: z.string().startsWith('Bearer '),
8181
}),
82+
cookies: z.object({
83+
sessionId: z.uuid(),
84+
theme: z.enum(['light', 'dark']).optional(),
85+
}),
8286
body: z.object({
8387
name: z.string().min(1).optional(),
8488
age: z.number().int().min(0).optional(),
@@ -89,13 +93,15 @@ app.put('/users/:id', {
8993
const { id } = ctx.req.validatedParams();
9094
const { notify, include } = ctx.req.validatedQueries();
9195
const { authorization } = ctx.req.validatedHeaders();
96+
const { sessionId, theme } = ctx.req.validatedCookies();
9297
const updates = ctx.req.validatedBody();
9398

9499
return ctx.res.json({
95100
userId: id,
96101
updates,
97102
willNotify: notify ?? false,
98103
token: authorization,
104+
session: { id: sessionId, theme },
99105
});
100106
},
101107
});
@@ -143,6 +149,42 @@ app.post('/users', {
143149
});
144150
```
145151

152+
## Body Parse Type
153+
154+
When defining content types, you can explicitly control how the request body is parsed using the `parseType` option. This is useful for non-standard content types or when you want to force a specific parsing method.
155+
156+
The available parse types are: `'json'`, `'form'`, `'text'`, `'binary'`, and `'auto'` (default).
157+
158+
```typescript
159+
const WebhookSchema = z.object({
160+
event: z.string(),
161+
payload: z.record(z.unknown()),
162+
});
163+
164+
app.post('/webhook', {
165+
requestSchema: zodRequestSchema({
166+
body: {
167+
content: {
168+
// Parse custom content type as JSON
169+
'application/vnd.custom+json': {
170+
schema: WebhookSchema,
171+
parseType: 'json',
172+
},
173+
// Parse binary data
174+
'application/octet-stream': {
175+
schema: z.instanceof(ArrayBuffer),
176+
parseType: 'binary',
177+
},
178+
},
179+
},
180+
}),
181+
handler: (ctx) => {
182+
const body = ctx.req.validatedBody();
183+
// ...
184+
},
185+
});
186+
```
187+
146188
## Error Handling
147189

148190
Kori provides flexible error handling for validation failures with multiple levels of customization.

docs/en/guide/routing.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ app.get('/files/:id{[0-9]+}', (ctx) => {
9292

9393
The type inference works by parsing the route string at compile time and extracting parameter names, helping prevent typos and improve IDE autocompletion.
9494

95-
**Important:** Type inference only works when you pass the route path as a string literal directly to the route method. It does **not** work for:
95+
Note that type inference only works when you pass the route path as a string literal directly to the route method. It does not work for:
9696

97-
- Routes defined with variables: `const path = '/users/:id'; app.get(path, ...)` - no inference
98-
- Path parameters from parent routes (defined in `createChild` prefix) - these are not included in the inferred type
97+
- Routes defined with variables: `const path = '/users/:id'; app.get(path, ...)`
98+
- Path parameters from parent routes (defined in `createChild` prefix)
9999

100-
Only parameters defined directly in the string literal of the route method itself will be type-safe.
100+
These parameters can still be accessed at runtime, but without autocomplete and typed as `string | undefined`.
101101

102102
### Accessing Individual Parameters
103103

0 commit comments

Comments
 (0)