Skip to content

Commit 08f191f

Browse files
committed
Update SKILL
1 parent 95b98fb commit 08f191f

2 files changed

Lines changed: 84 additions & 16 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SKILL.md

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,25 @@ npx @apidevtools/swagger-cli validate openapi.json
173173
> - SeaORM relation support (HasOne, BelongsTo, HasMany)
174174
> - No manual field synchronization
175175
176+
### Best Practices
177+
178+
| DO | DON'T |
179+
|----|-------|
180+
| Use `pick` to select only needed fields | Define manual structs that duplicate Model fields |
181+
| Use `omit` to exclude sensitive fields | Use `name` parameter unnecessarily |
182+
| Use full `crate::models::...` paths | Rely on implicit module resolution |
183+
| Define schema near route handlers | Scatter schemas across unrelated files |
184+
185+
**Primary Parameters (USE THESE):**
186+
- `pick = [...]` - Allowlist: include ONLY these fields
187+
- `omit = [...]` - Denylist: exclude these fields
188+
189+
**Advanced Parameters (USE SPARINGLY):**
190+
- `partial` - For PATCH endpoints only
191+
- `rename` - Only when API naming differs from model
192+
- `add` - Only when truly new fields needed (breaks `From` impl)
193+
- `name` - **AVOID** unless same-file Model reference (see below)
194+
176195
### Why Not Manual Structs?
177196

178197
```rust
@@ -223,9 +242,12 @@ schema_type!(InternalDTO from Model, ignore);
223242
schema_type!(LargeResponse from SomeType, clone = false);
224243
```
225244

226-
### Same-File Model Reference
245+
### Same-File Model Reference (When to Use `name`)
246+
247+
> **The `name` parameter is ONLY needed for same-file Model references.**
248+
> For cross-file references, use full paths and descriptive struct names instead.
227249
228-
When the model is in the same file, use simple name with `name` parameter:
250+
When defining Schema in the same file as Model (common for SeaORM entities):
229251

230252
```rust
231253
// In src/models/user.rs
@@ -237,10 +259,20 @@ pub struct Model {
237259

238260
pub enum UserStatus { Active, Inactive }
239261

240-
// Simple `Model` path works - module path inferred from file location
262+
// ✅ CORRECT: Same-file reference - use `name` for OpenAPI schema name
241263
vespera::schema_type!(Schema from Model, name = "UserSchema");
264+
265+
// ❌ WRONG: Using `name` for cross-file reference
266+
// schema_type!(Schema from crate::models::user::Model, name = "UserResponse");
267+
// ✅ CORRECT: Use descriptive struct name instead
268+
// schema_type!(UserResponse from crate::models::user::Model, omit = ["password"]);
242269
```
243270

271+
**Why avoid `name` for cross-file references?**
272+
- The struct name itself becomes the OpenAPI schema name
273+
- `UserResponse` is clearer than `Schema` with `name = "UserResponse"`
274+
- Less parameters = less complexity
275+
244276
### Cross-File References
245277

246278
Reference structs from other files using full module paths:
@@ -281,17 +313,29 @@ Json(model.into()) // Easy conversion!
281313

282314
### Parameters
283315

316+
**Recommended (Primary):**
317+
284318
| Parameter | Description | Example |
285319
|-----------|-------------|---------|
286320
| `pick` | Include only these fields | `pick = ["name", "email"]` |
287321
| `omit` | Exclude these fields | `omit = ["password"]` |
288-
| `rename` | Rename fields | `rename = [("id", "user_id")]` |
289-
| `add` | Add new fields (disables From impl) | `add = [("extra": String)]` |
290-
| `partial` | Make fields optional for PATCH | `partial` or `partial = ["name"]` |
291-
| `name` | Custom OpenAPI schema name | `name = "UserSchema"` |
292-
| `rename_all` | Serde rename strategy | `rename_all = "camelCase"` |
293-
| `ignore` | Skip Schema derive | bare keyword |
294-
| `clone` | Control Clone derive (default: true) | `clone = false` |
322+
323+
**Situational (Use When Needed):**
324+
325+
| Parameter | Description | When to Use |
326+
|-----------|-------------|-------------|
327+
| `partial` | Make fields optional | PATCH endpoints only |
328+
| `rename` | Rename fields | API naming differs from model |
329+
| `rename_all` | Serde rename strategy | Different casing needed |
330+
| `add` | Add new fields | New fields not in model (breaks `From` impl) |
331+
332+
**Avoid (Special Cases Only):**
333+
334+
| Parameter | Description | When to Use |
335+
|-----------|-------------|-------------|
336+
| `name` | Custom OpenAPI schema name | **Same-file Model reference only** |
337+
| `ignore` | Skip Schema derive | Internal DTOs not for OpenAPI |
338+
| `clone` | Control Clone derive | Large structs where Clone is expensive |
295339

296340
### SeaORM Integration (RECOMMENDED)
297341

@@ -334,7 +378,9 @@ vespera::schema_type!(Schema from Model, name = "MemoSchema");
334378
### Complete Example
335379

336380
```rust
337-
// src/models/user.rs (Sea-ORM entity)
381+
// ============================================
382+
// src/models/user.rs (SeaORM entity)
383+
// ============================================
338384
#[derive(Clone, Debug, DeriveEntityModel, Serialize, Deserialize)]
339385
#[sea_orm(table_name = "users")]
340386
pub struct Model {
@@ -347,10 +393,16 @@ pub struct Model {
347393
pub created_at: DateTimeWithTimeZone,
348394
}
349395

350-
// Generate Schema in same file - simple Model path
396+
// ✅ Same-file: use `name` parameter for OpenAPI schema name
351397
vespera::schema_type!(Schema from Model, name = "UserSchema");
352398

353-
// src/routes/users.rs - use full path for cross-file reference
399+
// ============================================
400+
// src/routes/users.rs (Route handlers)
401+
// ============================================
402+
use vespera::schema_type;
403+
404+
// ✅ Cross-file: use descriptive struct names + pick/omit
405+
// NO `name` parameter needed - struct name = OpenAPI schema name
354406
schema_type!(CreateUserRequest from crate::models::user::Model, pick = ["name", "email"]);
355407
schema_type!(UserResponse from crate::models::user::Model, omit = ["password_hash"]);
356408
schema_type!(UserPatch from crate::models::user::Model, omit = ["password_hash", "id"], partial);
@@ -370,6 +422,22 @@ pub async fn patch_user(
370422
}
371423
```
372424

425+
### Quick Reference
426+
427+
```rust
428+
// ✅ RECOMMENDED PATTERNS
429+
schema_type!(CreateUserRequest from crate::models::user::Model, pick = ["name", "email"]);
430+
schema_type!(UserResponse from crate::models::user::Model, omit = ["password_hash"]);
431+
schema_type!(UserListItem from crate::models::user::Model, pick = ["id", "name"]);
432+
433+
// ⚠️ USE SPARINGLY
434+
schema_type!(UserPatch from crate::models::user::Model, partial); // PATCH only
435+
schema_type!(Schema from Model, name = "UserSchema"); // Same-file only
436+
437+
// ❌ AVOID
438+
schema_type!(Schema from crate::models::user::Model, name = "UserResponse"); // Use struct name!
439+
```
440+
373441
---
374442

375443
## Merging Multiple Vespera Apps

0 commit comments

Comments
 (0)