Skip to content

Commit 9c26ca7

Browse files
📚 docs(Validation): Preparation for new validation approach
1 parent 3d694fe commit 9c26ca7

4 files changed

Lines changed: 247 additions & 67 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
sidebar_position: 99
3+
---
4+
5+
# Data Validation (Zod - Deprecated)
6+
7+
This data validation is came built-in with Yelix. It uses [Zod](https://zod.dev/).
8+
9+
## Initial Setup
10+
11+
Data Validation is built-in but by default it is not set. You need to set it in your main file.
12+
13+
```ts title="main.ts"
14+
import { Yelix, requestDataValidationMiddleware } from 'jsr:@murat/yelix';
15+
16+
export async function startServer() {
17+
const app = new Yelix();
18+
19+
// highlight-next-line
20+
app.setMiddleware('dataValidation', requestDataValidationMiddleware);
21+
22+
app.serve();
23+
}
24+
25+
await startServer();
26+
27+
```
28+
29+
## Query Parameters
30+
31+
```ts title="hello.ts"
32+
import { Ctx, ValidationType } from "jsr:@murat/yelix";
33+
import { z } from "npm:zod@^3.24.1";
34+
35+
export async function GET(ctx: Ctx) {
36+
// highlight-start
37+
const requestData = ctx.get('dataValidation').user;
38+
const query: QueryType = requestData.query;
39+
// highlight-end
40+
41+
return await ctx.text('Hello, ' + query.name, 200);
42+
}
43+
44+
export const path = '/api/hello';
45+
// highlight-next-line
46+
export const middlewares = ['dataValidation'];
47+
48+
// highlight-start
49+
export const validation: ValidationType = {
50+
query: {
51+
name: z.string(),
52+
},
53+
};
54+
const querySchema = z.object(validation.query as z.ZodRawShape);
55+
type QueryType = z.infer<typeof querySchema>;
56+
// highlight-end
57+
```
58+
59+
## Body Parameters
60+
61+
```ts title="hello.ts"
62+
import { Ctx, ValidationType } from "jsr:@murat/yelix";
63+
import { z } from "npm:zod@^3.24.1";
64+
65+
export async function POST(ctx: Ctx) {
66+
// highlight-start
67+
const requestData = ctx.get('dataValidation').user;
68+
const {
69+
fullname,
70+
username,
71+
email,
72+
password,
73+
}: BodyType = requestData.body;
74+
// highlight-end
75+
76+
return await ctx.text('Hello, ' + fullname, 200);
77+
}
78+
79+
export const path = '/api/hello';
80+
// highlight-next-line
81+
export const middlewares = ['dataValidation'];
82+
83+
// highlight-start
84+
export const validation: ValidationType = {
85+
body: z.object({
86+
fullname: z.string().min(3).max(255),
87+
username: z
88+
.string()
89+
.min(3)
90+
.max(255)
91+
.refine((value) => !/@/.test(value), {
92+
message: 'Username should not contain @',
93+
})
94+
.refine((value) => !/\s/.test(value), {
95+
message: 'Username should not contain whitespace',
96+
})
97+
.refine((value) => value === value.toLowerCase(), {
98+
message: 'Username should be lowercase',
99+
}),
100+
email: z.string().email(),
101+
password: z.string().min(8).max(255),
102+
}),
103+
};
104+
type BodyType = z.infer<typeof validation.body>;
105+
// highlight-end
106+
```

docs/endpoints/data-validation.md

Lines changed: 128 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,105 +2,166 @@
22
sidebar_position: 3
33
---
44

5-
# Data Validation (Zod)
5+
# Data Validation
66

7-
This data validation is came built-in with Yelix. It uses [Zod](https://zod.dev/).
7+
Yelix comes with a powerful built-in data validation system inspired by Zod but with additional features.
88

99
## Initial Setup
1010

11-
Data Validation is built-in but by default it is not set. You need to set it in your main file.
11+
Data Validation is built-in but needs to be enabled in your main file.
1212

1313
```ts title="main.ts"
14-
import { Yelix, requestDataValidationMiddleware } from 'jsr:@murat/yelix';
14+
import { Yelix, requestDataValidationYelixMiddleware } from 'jsr:@murat/yelix';
1515

1616
export async function startServer() {
1717
const app = new Yelix();
18-
19-
// highlight-next-line
20-
app.setMiddleware('dataValidation', requestDataValidationMiddleware);
21-
18+
app.setMiddleware('dataValidation', requestDataValidationYelixMiddleware);
2219
app.serve();
2320
}
2421

2522
await startServer();
26-
2723
```
2824

29-
## Query Parameters
25+
## Basic Example
3026

3127
```ts title="hello.ts"
32-
import { Ctx, ValidationType } from "jsr:@murat/yelix";
33-
import { z } from "npm:zod@^3.24.1";
28+
import { Ctx, ValidationType, inp } from "jsr:@murat/yelix";
3429

35-
export async function GET(ctx: Ctx) {
36-
// highlight-start
30+
export async function POST(ctx: Ctx) {
3731
const requestData = ctx.get('dataValidation').user;
38-
const query: QueryType = requestData.query;
39-
// highlight-end
40-
41-
return await ctx.text('Hello, ' + query.name, 200);
32+
const { username, email } = requestData.body;
33+
return await ctx.text(`Hello, ${username}!`, 200);
4234
}
4335

4436
export const path = '/api/hello';
45-
// highlight-next-line
4637
export const middlewares = ['dataValidation'];
4738

48-
// highlight-start
4939
export const validation: ValidationType = {
50-
query: {
51-
name: z.string(),
52-
},
40+
body: inp().object({
41+
username: inp().string().min(3).max(255),
42+
email: inp().string().email()
43+
})
5344
};
54-
const querySchema = z.object(validation.query as z.ZodRawShape);
55-
type QueryType = z.infer<typeof querySchema>;
56-
// highlight-end
5745
```
5846

59-
## Body Parameters
47+
## Available Validators
48+
49+
### String Validation
50+
```ts
51+
inp().string()
52+
.min(3) // Minimum length
53+
.max(255) // Maximum length
54+
.length(10) // Exact length
55+
.email() // Email format
56+
.url() // URL format
57+
.regex(/pattern/) // Regular expression
58+
.includes("text") // Contains text
59+
.startsWith("prefix") // Starts with
60+
.endsWith("suffix") // Ends with
61+
.trim() // Trim whitespace
62+
.toLowerCase() // Convert to lowercase
63+
.toUpperCase() // Convert to uppercase
64+
.ip() // IP address (v4/v6)
65+
.date() // Date string format
66+
.time() // Time string format
67+
.datetime() // ISO datetime format
68+
.base64() // Base64 string
69+
.optional() // Make field optional
70+
```
6071

61-
```ts title="hello.ts"
62-
import { Ctx, ValidationType } from "jsr:@murat/yelix";
63-
import { z } from "npm:zod@^3.24.1";
72+
### Number Validation
73+
```ts
74+
inp().number()
75+
.min(0) // Minimum value
76+
.max(100) // Maximum value
77+
.range(0, 100) // Value range
78+
.integer() // Must be integer
79+
.positive() // Must be positive
80+
.negative() // Must be negative
81+
.multipleOf(5) // Multiple of value
82+
.finite() // Must be finite
83+
.safe() // Safe integer
84+
.optional() // Make field optional
85+
```
6486

65-
export async function POST(ctx: Ctx) {
66-
// highlight-start
67-
const requestData = ctx.get('dataValidation').user;
68-
const {
69-
fullname,
70-
username,
71-
email,
72-
password,
73-
}: BodyType = requestData.body;
74-
// highlight-end
75-
76-
return await ctx.text('Hello, ' + fullname, 200);
77-
}
87+
### Array Validation
88+
```ts
89+
inp().array()
90+
.min(1) // Minimum length
91+
.max(10) // Maximum length
92+
.length(5) // Exact length
93+
.notEmpty() // Must not be empty
94+
.unique() // All elements unique
95+
.includes(value) // Must include value
96+
.every(validator) // All items must match
97+
.some(validator) // Some items must match
98+
.optional() // Make field optional
99+
```
78100

79-
export const path = '/api/hello';
80-
// highlight-next-line
81-
export const middlewares = ['dataValidation'];
101+
### Object Validation
102+
```ts
103+
inp().object({
104+
name: inp().string(),
105+
age: inp().number(),
106+
tags: inp().array()
107+
})
108+
.hasKey("field") // Must have key
109+
.minKeys(1) // Minimum keys
110+
.maxKeys(10) // Maximum keys
111+
.exactKeys(["id", "name"]) // Must have exact keys
112+
.optional() // Make field optional
113+
```
82114

83-
// highlight-start
84-
export const validation: ValidationType = {
85-
body: z.object({
86-
fullname: z.string().min(3).max(255),
87-
username: z
88-
.string()
89-
.min(3)
90-
.max(255)
91-
.refine((value) => !/@/.test(value), {
92-
message: 'Username should not contain @',
93-
})
94-
.refine((value) => !/\s/.test(value), {
95-
message: 'Username should not contain whitespace',
96-
})
97-
.refine((value) => value === value.toLowerCase(), {
98-
message: 'Username should be lowercase',
99-
}),
100-
email: z.string().email(),
101-
password: z.string().min(8).max(255),
115+
### Date Validation
116+
```ts
117+
inp().date()
118+
.min(new Date("2024-01-01")) // Minimum date
119+
.max(new Date("2024-12-31")) // Maximum date
120+
.format("yyyy-MM-dd") // Format date
121+
.timezone("America/New_York") // Set timezone
122+
.future() // Must be future
123+
.past() // Must be past
124+
.weekday([1,2,3,4,5]) // Valid weekdays
125+
.age(18) // Minimum age
126+
.optional() // Make field optional
127+
```
128+
129+
### File Validation
130+
```ts
131+
inp().file()
132+
.multipleFiles() // Allow multiple files
133+
.minFilesCount(1) // Minimum files
134+
.maxFilesCount(5) // Maximum files
135+
.minSize(1024) // Minimum size (bytes)
136+
.maxSize(5 * 1024 * 1024) // Maximum size (bytes)
137+
.mimeType(['image/jpeg', 'image/png']) // Valid mime types
138+
.optional() // Make field optional
139+
```
140+
141+
## Complete Example
142+
143+
```ts
144+
export const validation: ValidationTypeBETA = {
145+
query: {
146+
page: inp().number().integer().min(1).optional(),
147+
limit: inp().number().integer().range(1, 100)
148+
},
149+
body: inp().object({
150+
username: inp().string().min(3).max(255),
151+
email: inp().string().email(),
152+
age: inp().number().range(18, 99),
153+
profile: inp().object({
154+
bio: inp().string().max(1000).optional(),
155+
interests: inp().array().every(inp().string()).max(10)
156+
}),
157+
avatar: inp().file().maxSize(5 * 1024 * 1024).mimeType(['image/jpeg', 'image/png'])
102158
}),
159+
formData: {
160+
files: inp().file()
161+
.multipleFiles()
162+
.maxFilesCount(5)
163+
.maxSize(10 * 1024 * 1024)
164+
.mimeType(['application/pdf'])
165+
}
103166
};
104-
type BodyType = z.infer<typeof validation.body>;
105-
// highlight-end
106167
```

docs/testing/_category_.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"label": "Testing",
3+
"position": 3,
4+
"link": {
5+
"type": "generated-index",
6+
"description": "Information about testing the API."
7+
}
8+
}

docs/testing/testing-endpoint.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
sidebar_position: 1
3+
---
4+
5+
# Testing Endpoint

0 commit comments

Comments
 (0)