Skip to content

Commit 3fdacd9

Browse files
committed
feat(request): add enhanced request handling with automatic parsing 🦋
- Add DeserveRequest class with query and parameter parsing methods - Add detailed request handling documentation - Reorder exports to prioritize Request functionality - Update Handler to pass DeserveRequest instead of native Request - Update navigation and README with new documentation links - Update RouterHandler type to use DeserveRequest
1 parent 50192b7 commit 3fdacd9

7 files changed

Lines changed: 226 additions & 9 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ Follow our [installing guide](https://docs-deserve.neabyte.com/getting-started/i
2525
- **Core Concepts**
2626
- [File-based Routing](https://docs-deserve.neabyte.com/core-concepts/file-based-routing) - How file structure becomes API endpoints
2727
- [Route Patterns](https://docs-deserve.neabyte.com/core-concepts/route-patterns) - Dynamic routes and parameter matching
28-
- [HTTP Methods](https://docs-deserve.neabyte.com/core-concepts/http-methods) - Supported HTTP methods
28+
- [HTTP Methods](https://docs-deserve.neabyte.com/core-concepts/http-methods) - All supported HTTP methods
29+
- [Request Handling](https://docs-deserve.neabyte.com/core-concepts/request-handling) - Enhanced request object with automatic parsing
2930

3031
- **Middleware**
3132
- [Global Middleware](https://docs-deserve.neabyte.com/middleware/global) - Cross-cutting functionality
@@ -45,7 +46,7 @@ Follow our [installing guide](https://docs-deserve.neabyte.com/getting-started/i
4546
- [Multiple Directories](https://docs-deserve.neabyte.com/static-file/multiple) - Serve from multiple locations
4647

4748
- **Error Handling**
48-
- [Object Details](https://docs-deserve.neabyte.com/error-handling/object-details) - Comprehensive error information
49+
- [Object Details](https://docs-deserve.neabyte.com/error-handling/object-details) - Detailed error information
4950

5051
## Contributing
5152

docs/.vitepress/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export default defineConfig({
2424
items: [
2525
{ text: 'File-based Routing', link: '/core-concepts/file-based-routing' },
2626
{ text: 'Route Patterns', link: '/core-concepts/route-patterns' },
27-
{ text: 'HTTP Methods', link: '/core-concepts/http-methods' }
27+
{ text: 'HTTP Methods', link: '/core-concepts/http-methods' },
28+
{ text: 'Request Handling', link: '/core-concepts/request-handling' }
2829
]
2930
},
3031
{
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Request Handling
2+
3+
> **Reference**: [Deno Request API Documentation](https://docs.deno.com/deploy/classic/api/runtime-request/)
4+
5+
Deserve provides an enhanced `DeserveRequest` class that extends the native `Request` object with methods for accessing query and route parameters automatically.
6+
7+
## Basic Usage
8+
9+
Import `DeserveRequest` and use it in your route handlers:
10+
11+
```typescript
12+
import { Send, DeserveRequest } from '@neabyte/deserve'
13+
14+
// routes/users.ts
15+
export function GET(req: DeserveRequest): Response {
16+
const query = req.query()
17+
return Send.json({ query })
18+
}
19+
```
20+
21+
## Query Parameters
22+
23+
Access URL query parameters with automatic parsing:
24+
25+
### Single Query Parameters
26+
```typescript
27+
// URL: /search?q=deno&limit=10
28+
export function GET(req: DeserveRequest): Response {
29+
const query = req.query() // Expected: { q: 'deno', limit: '10' }
30+
return Send.json({
31+
search: query.q,
32+
limit: parseInt(query.limit || '10')
33+
})
34+
}
35+
```
36+
37+
### Multiple Values for Same Key
38+
```typescript
39+
// URL: /search?tags=deno&tags=typescript&tags=javascript
40+
export function GET(req: DeserveRequest): Response {
41+
const tags = req.queries('tags') // Expected: ['deno', 'typescript', 'javascript']
42+
return Send.json({ tags })
43+
}
44+
```
45+
46+
### Complete Query Object
47+
```typescript
48+
// URL: /api/users?page=1&limit=20&sort=name&order=asc
49+
export function GET(req: DeserveRequest): Response {
50+
const query = req.query() // Expected: { page: '1', limit: '20', sort: 'name', order: 'asc' }
51+
return Send.json({
52+
page: parseInt(query.page || '1'),
53+
limit: parseInt(query.limit || '10'),
54+
sort: query.sort || 'id',
55+
order: query.order || 'asc'
56+
})
57+
}
58+
```
59+
60+
## Route Parameters
61+
62+
Access dynamic route parameters from file-based routing:
63+
64+
### Single Parameter
65+
```typescript
66+
// routes/users/[id].ts
67+
// URL: /users/123
68+
export function GET(req: DeserveRequest): Response {
69+
const id = req.param('id') // Expected: '123'
70+
return Send.json({ userId: id })
71+
}
72+
```
73+
74+
### Multiple Parameters
75+
```typescript
76+
// routes/users/[id]/posts/[postId].ts
77+
// URL: /users/123/posts/456
78+
export function GET(req: DeserveRequest): Response {
79+
const id = req.param('id')
80+
const postId = req.param('postId') // Expected: id='123', postId='456'
81+
return Send.json({ userId: id, postId })
82+
}
83+
```
84+
85+
### All Parameters
86+
```typescript
87+
// routes/api/v1/users/[userId]/posts/[postId]/comments/[commentId].ts
88+
// URL: /api/v1/users/123/posts/456/comments/789
89+
export function GET(req: DeserveRequest): Response {
90+
const params = req.params() // Expected: { userId: '123', postId: '456', commentId: '789' }
91+
return Send.json(params)
92+
}
93+
```
94+
95+
## Method Reference
96+
97+
### `req.query()`
98+
Returns all query parameters as an object.
99+
100+
```typescript
101+
// URL: /search?q=deno&limit=10
102+
const query = req.query()
103+
// Expected: { q: 'deno', limit: '10' }
104+
```
105+
106+
### `req.queries(key)`
107+
Returns all values for a specific query parameter key.
108+
109+
```typescript
110+
// URL: /search?tags=deno&tags=typescript
111+
const tags = req.queries('tags')
112+
// Expected: ['deno', 'typescript']
113+
```
114+
115+
### `req.param(key)`
116+
Returns a single route parameter value.
117+
118+
```typescript
119+
// Route: /users/[id]
120+
// URL: /users/123
121+
const id = req.param('id')
122+
// Expected: '123'
123+
```
124+
125+
### `req.params()`
126+
Returns all route parameters as an object.
127+
128+
```typescript
129+
// Route: /users/[id]/posts/[postId]
130+
// URL: /users/123/posts/456
131+
const params = req.params()
132+
// Expected: { id: '123', postId: '456' }
133+
```
134+
135+
## Best Practices
136+
137+
1. **Validate parameters** - Check format and type before using
138+
2. **Provide defaults** - Use fallback values for optional parameters
139+
3. **Handle missing values** - Check for undefined/null values
140+
4. **Use appropriate types** - Convert strings to numbers when needed
141+
5. **Keep parameter names descriptive** - Use clear, meaningful names
142+
143+
## Next Steps
144+
145+
- [File-based Routing](/core-concepts/file-based-routing) - Understanding route structure
146+
- [Route Patterns](/core-concepts/route-patterns) - Dynamic parameter patterns
147+
- [HTTP Methods](/core-concepts/http-methods) - Supported request methods

src/Handler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { serveDir, type ServeDirOptions } from '@std/http/file-server'
22
import type { ErrorMiddleware, RouterHandler, RouterMiddleware } from '@app/Types.ts'
3+
import { DeserveRequest } from '@app/Request.ts'
34

45
/**
56
* Executes the appropriate handler method for the request.
@@ -19,7 +20,8 @@ async function executeHandler(
1920
): Promise<Response> {
2021
if (module[method]) {
2122
try {
22-
return await module[method](req, params)
23+
const deserveReq = new DeserveRequest(req, params)
24+
return await module[method](deserveReq, params)
2325
} catch (error) {
2426
if (errorMiddleware) {
2527
const customResponse = errorMiddleware(req, {

src/Request.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Request class with automatic query parsing.
3+
* @description Extends Request with convenient methods.
4+
*/
5+
export class DeserveRequest extends Request {
6+
/** Route parameters extracted from URL pattern matching */
7+
private urlParams: Record<string, string>
8+
9+
/**
10+
* Create a new DeserveRequest instance.
11+
* @param req - Native Request object
12+
* @param params - Route parameters from URL pattern matching
13+
*/
14+
constructor(req: Request, params: Record<string, string>) {
15+
super(req)
16+
this.urlParams = params
17+
}
18+
19+
/**
20+
* Get a single route parameter value.
21+
* @param key - Route parameter key
22+
* @returns Parameter value or empty string
23+
*/
24+
param(key: string): string {
25+
return this.urlParams[key] || ''
26+
}
27+
28+
/**
29+
* Get all route parameters as an object.
30+
* @returns Object with route parameter key-value pairs
31+
*/
32+
params(): Record<string, string> {
33+
return this.urlParams
34+
}
35+
36+
/**
37+
* Get all query parameters as an object.
38+
* @returns Object with query parameter key-value pairs
39+
*/
40+
query(): Record<string, string> {
41+
const url = new URL(this.url)
42+
const result: Record<string, string> = {}
43+
url.searchParams.forEach((value, key) => {
44+
result[key] = value
45+
})
46+
return result
47+
}
48+
49+
/**
50+
* Get multiple values for the same query parameter key.
51+
* @param key - Query parameter key
52+
* @returns Array of values for the key
53+
*/
54+
queries(key: string): string[] {
55+
const url = new URL(this.url)
56+
return url.searchParams.getAll(key)
57+
}
58+
}

src/Types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { DeserveRequest } from '@app/Request.ts'
2+
13
/**
24
* Error middleware function type.
35
* @param req - HTTP request object
@@ -16,12 +18,12 @@ export type ErrorMiddleware = (
1618

1719
/**
1820
* Route handler function type.
19-
* @param req - HTTP request object
21+
* @param req - Enhanced request object with query parsing
2022
* @param params - Route parameters from URL
2123
* @returns HTTP response or promise
2224
*/
2325
export type RouterHandler = (
24-
req: Request,
26+
req: DeserveRequest,
2527
params: Record<string, string>
2628
) => Response | Promise<Response>
2729

src/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
/**
2-
* Response utility for HTTP responses.
3-
* @description Provides static methods for responses.
2+
* Enhanced Request class with automatic parsing.
3+
* @description Extends native Request with convenient methods.
44
*/
5-
export * from '@app/Send.ts'
5+
export * from '@app/Request.ts'
66

77
/**
88
* Router class for file-based routing.
99
* @description File-based routing with Deno serve API.
1010
*/
1111
export * from '@app/Router.ts'
1212

13+
/**
14+
* Response utility for HTTP responses.
15+
* @description Provides static methods for responses.
16+
*/
17+
export * from '@app/Send.ts'
18+
1319
/**
1420
* Type definitions for router configuration and handlers.
1521
* @description TypeScript interfaces and types.

0 commit comments

Comments
 (0)