omgkit 2.1.1 → 2.3.0
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/package.json +1 -1
- package/plugin/skills/databases/mongodb/SKILL.md +81 -28
- package/plugin/skills/databases/prisma/SKILL.md +87 -32
- package/plugin/skills/databases/redis/SKILL.md +80 -27
- package/plugin/skills/devops/aws/SKILL.md +80 -26
- package/plugin/skills/devops/github-actions/SKILL.md +84 -32
- package/plugin/skills/devops/kubernetes/SKILL.md +94 -32
- package/plugin/skills/devops/performance-profiling/SKILL.md +59 -863
- package/plugin/skills/frameworks/django/SKILL.md +158 -24
- package/plugin/skills/frameworks/express/SKILL.md +153 -33
- package/plugin/skills/frameworks/fastapi/SKILL.md +153 -34
- package/plugin/skills/frameworks/laravel/SKILL.md +146 -33
- package/plugin/skills/frameworks/nestjs/SKILL.md +137 -25
- package/plugin/skills/frameworks/rails/SKILL.md +594 -28
- package/plugin/skills/frameworks/react/SKILL.md +94 -962
- package/plugin/skills/frameworks/spring/SKILL.md +528 -35
- package/plugin/skills/frameworks/vue/SKILL.md +147 -25
- package/plugin/skills/frontend/accessibility/SKILL.md +145 -36
- package/plugin/skills/frontend/frontend-design/SKILL.md +114 -29
- package/plugin/skills/frontend/responsive/SKILL.md +131 -28
- package/plugin/skills/frontend/shadcn-ui/SKILL.md +133 -43
- package/plugin/skills/frontend/tailwindcss/SKILL.md +105 -37
- package/plugin/skills/frontend/threejs/SKILL.md +110 -35
- package/plugin/skills/languages/javascript/SKILL.md +195 -34
- package/plugin/skills/methodology/brainstorming/SKILL.md +98 -30
- package/plugin/skills/methodology/defense-in-depth/SKILL.md +83 -37
- package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +92 -31
- package/plugin/skills/methodology/executing-plans/SKILL.md +117 -28
- package/plugin/skills/methodology/finishing-development-branch/SKILL.md +111 -32
- package/plugin/skills/methodology/problem-solving/SKILL.md +65 -311
- package/plugin/skills/methodology/receiving-code-review/SKILL.md +76 -27
- package/plugin/skills/methodology/requesting-code-review/SKILL.md +93 -22
- package/plugin/skills/methodology/root-cause-tracing/SKILL.md +75 -40
- package/plugin/skills/methodology/sequential-thinking/SKILL.md +75 -224
- package/plugin/skills/methodology/systematic-debugging/SKILL.md +81 -35
- package/plugin/skills/methodology/test-driven-development/SKILL.md +120 -26
- package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +88 -35
- package/plugin/skills/methodology/token-optimization/SKILL.md +73 -34
- package/plugin/skills/methodology/verification-before-completion/SKILL.md +128 -28
- package/plugin/skills/methodology/writing-plans/SKILL.md +105 -20
- package/plugin/skills/omega/omega-architecture/SKILL.md +178 -40
- package/plugin/skills/omega/omega-coding/SKILL.md +247 -41
- package/plugin/skills/omega/omega-sprint/SKILL.md +208 -46
- package/plugin/skills/omega/omega-testing/SKILL.md +253 -42
- package/plugin/skills/omega/omega-thinking/SKILL.md +263 -51
- package/plugin/skills/security/better-auth/SKILL.md +83 -34
- package/plugin/skills/security/oauth/SKILL.md +118 -35
- package/plugin/skills/security/owasp/SKILL.md +112 -35
- package/plugin/skills/testing/playwright/SKILL.md +141 -38
- package/plugin/skills/testing/pytest/SKILL.md +137 -38
- package/plugin/skills/testing/vitest/SKILL.md +124 -39
- package/plugin/skills/tools/document-processing/SKILL.md +111 -838
- package/plugin/skills/tools/image-processing/SKILL.md +126 -659
- package/plugin/skills/tools/mcp-development/SKILL.md +85 -758
- package/plugin/skills/tools/media-processing/SKILL.md +118 -735
- package/plugin/stdrules/SKILL_STANDARDS.md +490 -0
|
@@ -1,47 +1,181 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: django
|
|
3
|
-
description: Django
|
|
2
|
+
name: building-django-apps
|
|
3
|
+
description: Builds enterprise Django applications with DRF, ORM optimization, async views, and Celery tasks. Use when creating Python web apps, REST APIs, or full-stack Django projects.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Django
|
|
6
|
+
# Django
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Quick Start
|
|
9
9
|
|
|
10
|
-
### Model
|
|
11
10
|
```python
|
|
12
|
-
|
|
11
|
+
# views.py
|
|
12
|
+
from rest_framework import viewsets
|
|
13
|
+
from rest_framework.decorators import api_view
|
|
14
|
+
from rest_framework.response import Response
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
@api_view(['GET'])
|
|
17
|
+
def health_check(request):
|
|
18
|
+
return Response({'status': 'ok'})
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
21
|
+
queryset = User.objects.all()
|
|
22
|
+
serializer_class = UserSerializer
|
|
20
23
|
```
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
| Feature | Description | Guide |
|
|
28
|
+
|---------|-------------|-------|
|
|
29
|
+
| Models | ORM, relationships, managers | [MODELS.md](MODELS.md) |
|
|
30
|
+
| Views | ViewSets, APIView, async views | [VIEWS.md](VIEWS.md) |
|
|
31
|
+
| Serializers | Validation, nested data | [SERIALIZERS.md](SERIALIZERS.md) |
|
|
32
|
+
| Auth | JWT, permissions, policies | [AUTH.md](AUTH.md) |
|
|
33
|
+
| Queries | select_related, prefetch, N+1 | [QUERIES.md](QUERIES.md) |
|
|
34
|
+
| Testing | pytest-django, fixtures | [TESTING.md](TESTING.md) |
|
|
35
|
+
|
|
36
|
+
## Common Patterns
|
|
37
|
+
|
|
38
|
+
### Model with Relationships
|
|
39
|
+
|
|
23
40
|
```python
|
|
24
|
-
from django.
|
|
25
|
-
from
|
|
41
|
+
from django.db import models
|
|
42
|
+
from uuid import uuid4
|
|
43
|
+
|
|
44
|
+
class User(AbstractUser):
|
|
45
|
+
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
|
|
46
|
+
email = models.EmailField(unique=True)
|
|
47
|
+
|
|
48
|
+
USERNAME_FIELD = 'email'
|
|
26
49
|
|
|
27
|
-
class
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
50
|
+
class Meta:
|
|
51
|
+
db_table = 'users'
|
|
52
|
+
indexes = [models.Index(fields=['email'])]
|
|
53
|
+
|
|
54
|
+
class Organization(models.Model):
|
|
55
|
+
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
|
|
56
|
+
name = models.CharField(max_length=255)
|
|
57
|
+
slug = models.SlugField(unique=True)
|
|
58
|
+
owner = models.ForeignKey(User, on_delete=models.PROTECT, related_name='owned_orgs')
|
|
59
|
+
members = models.ManyToManyField(User, through='Membership', related_name='organizations')
|
|
31
60
|
```
|
|
32
61
|
|
|
33
|
-
###
|
|
62
|
+
### DRF Serializers
|
|
63
|
+
|
|
34
64
|
```python
|
|
35
65
|
from rest_framework import serializers
|
|
36
66
|
|
|
37
67
|
class UserSerializer(serializers.ModelSerializer):
|
|
68
|
+
full_name = serializers.SerializerMethodField()
|
|
69
|
+
|
|
38
70
|
class Meta:
|
|
39
71
|
model = User
|
|
40
|
-
fields = ['id', 'email', 'created_at']
|
|
72
|
+
fields = ['id', 'email', 'full_name', 'created_at']
|
|
73
|
+
read_only_fields = ['id', 'created_at']
|
|
74
|
+
|
|
75
|
+
def get_full_name(self, obj):
|
|
76
|
+
return f"{obj.first_name} {obj.last_name}".strip()
|
|
77
|
+
|
|
78
|
+
class UserCreateSerializer(serializers.ModelSerializer):
|
|
79
|
+
password = serializers.CharField(write_only=True, min_length=8)
|
|
80
|
+
password_confirm = serializers.CharField(write_only=True)
|
|
81
|
+
|
|
82
|
+
class Meta:
|
|
83
|
+
model = User
|
|
84
|
+
fields = ['email', 'password', 'password_confirm']
|
|
85
|
+
|
|
86
|
+
def validate(self, attrs):
|
|
87
|
+
if attrs['password'] != attrs['password_confirm']:
|
|
88
|
+
raise serializers.ValidationError({'password_confirm': 'Passwords must match'})
|
|
89
|
+
return attrs
|
|
90
|
+
|
|
91
|
+
def create(self, validated_data):
|
|
92
|
+
validated_data.pop('password_confirm')
|
|
93
|
+
return User.objects.create_user(**validated_data)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### ViewSet with Permissions
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from rest_framework import viewsets, permissions
|
|
100
|
+
from rest_framework.decorators import action
|
|
101
|
+
from rest_framework.response import Response
|
|
102
|
+
|
|
103
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
104
|
+
permission_classes = [permissions.IsAuthenticated]
|
|
105
|
+
|
|
106
|
+
def get_queryset(self):
|
|
107
|
+
return User.objects.select_related('profile').prefetch_related('organizations')
|
|
108
|
+
|
|
109
|
+
def get_serializer_class(self):
|
|
110
|
+
if self.action == 'create':
|
|
111
|
+
return UserCreateSerializer
|
|
112
|
+
return UserSerializer
|
|
113
|
+
|
|
114
|
+
@action(detail=False, methods=['get', 'patch'])
|
|
115
|
+
def me(self, request):
|
|
116
|
+
if request.method == 'GET':
|
|
117
|
+
return Response(UserSerializer(request.user).data)
|
|
118
|
+
serializer = UserSerializer(request.user, data=request.data, partial=True)
|
|
119
|
+
serializer.is_valid(raise_exception=True)
|
|
120
|
+
serializer.save()
|
|
121
|
+
return Response(serializer.data)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Workflows
|
|
125
|
+
|
|
126
|
+
### API Development
|
|
127
|
+
|
|
128
|
+
1. Create model and migration
|
|
129
|
+
2. Create serializer with validation
|
|
130
|
+
3. Create ViewSet or APIView
|
|
131
|
+
4. Configure URL routing
|
|
132
|
+
5. Write tests with pytest-django
|
|
133
|
+
|
|
134
|
+
### Query Optimization
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# Avoid N+1 queries
|
|
138
|
+
users = User.objects.select_related('profile').prefetch_related(
|
|
139
|
+
Prefetch('organizations', queryset=Organization.objects.only('id', 'name'))
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Use values() for lightweight queries
|
|
143
|
+
User.objects.values('id', 'email', 'created_at')
|
|
144
|
+
|
|
145
|
+
# Annotate for aggregations
|
|
146
|
+
Organization.objects.annotate(member_count=Count('members'))
|
|
41
147
|
```
|
|
42
148
|
|
|
43
149
|
## Best Practices
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
150
|
+
|
|
151
|
+
| Do | Avoid |
|
|
152
|
+
|----|-------|
|
|
153
|
+
| Use `select_related`/`prefetch_related` | N+1 queries |
|
|
154
|
+
| Use serializers for validation | Manual validation |
|
|
155
|
+
| Use custom managers | Query logic in views |
|
|
156
|
+
| Use signals sparingly | Overusing signals |
|
|
157
|
+
| Use Celery for heavy tasks | Sync operations for I/O |
|
|
158
|
+
|
|
159
|
+
## Project Structure
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
project/
|
|
163
|
+
├── manage.py
|
|
164
|
+
├── config/
|
|
165
|
+
│ ├── settings/
|
|
166
|
+
│ ├── urls.py
|
|
167
|
+
│ └── wsgi.py
|
|
168
|
+
├── apps/
|
|
169
|
+
│ ├── users/
|
|
170
|
+
│ │ ├── models.py
|
|
171
|
+
│ │ ├── serializers.py
|
|
172
|
+
│ │ ├── views.py
|
|
173
|
+
│ │ └── tests/
|
|
174
|
+
│ └── organizations/
|
|
175
|
+
├── common/
|
|
176
|
+
│ ├── permissions.py
|
|
177
|
+
│ └── pagination.py
|
|
178
|
+
└── tests/
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
For detailed examples and patterns, see reference files above.
|
|
@@ -1,55 +1,175 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: express
|
|
3
|
-
description: Express.js
|
|
2
|
+
name: building-express-apis
|
|
3
|
+
description: Builds production Express.js APIs with TypeScript, middleware patterns, authentication, and error handling. Use when creating Node.js backends, REST APIs, or Express applications.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Express.js
|
|
6
|
+
# Express.js
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Quick Start
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
```javascript
|
|
10
|
+
```typescript
|
|
12
11
|
import express from 'express';
|
|
12
|
+
import cors from 'cors';
|
|
13
|
+
import helmet from 'helmet';
|
|
13
14
|
|
|
14
15
|
const app = express();
|
|
16
|
+
|
|
17
|
+
app.use(helmet());
|
|
18
|
+
app.use(cors());
|
|
15
19
|
app.use(express.json());
|
|
16
|
-
```
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
app.get('/users', async (req, res) => {
|
|
21
|
-
const users = await db.users.findMany();
|
|
22
|
-
res.json(users);
|
|
21
|
+
app.get('/api/health', (req, res) => {
|
|
22
|
+
res.json({ status: 'ok' });
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
app.
|
|
26
|
-
const user = await db.users.create(req.body);
|
|
27
|
-
res.status(201).json(user);
|
|
28
|
-
});
|
|
25
|
+
app.listen(3000);
|
|
29
26
|
```
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
| Feature | Description | Guide |
|
|
31
|
+
|---------|-------------|-------|
|
|
32
|
+
| Project Setup | TypeScript config, middleware stack | [SETUP.md](SETUP.md) |
|
|
33
|
+
| Routing | Controllers, validation, async handlers | [ROUTING.md](ROUTING.md) |
|
|
34
|
+
| Middleware | Auth, validation, error handling | [MIDDLEWARE.md](MIDDLEWARE.md) |
|
|
35
|
+
| Database | Prisma/TypeORM integration | [DATABASE.md](DATABASE.md) |
|
|
36
|
+
| Testing | Jest, supertest patterns | [TESTING.md](TESTING.md) |
|
|
37
|
+
| Deployment | Docker, PM2, production config | [DEPLOYMENT.md](DEPLOYMENT.md) |
|
|
38
|
+
|
|
39
|
+
## Common Patterns
|
|
40
|
+
|
|
41
|
+
### Controller Pattern
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// controllers/users.ts
|
|
45
|
+
import { Request, Response, NextFunction } from 'express';
|
|
46
|
+
import { UserService } from '../services/UserService';
|
|
47
|
+
|
|
48
|
+
export class UserController {
|
|
49
|
+
constructor(private userService: UserService) {}
|
|
50
|
+
|
|
51
|
+
getAll = async (req: Request, res: Response, next: NextFunction) => {
|
|
52
|
+
try {
|
|
53
|
+
const users = await this.userService.findAll();
|
|
54
|
+
res.json(users);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
next(error);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
getById = async (req: Request, res: Response, next: NextFunction) => {
|
|
61
|
+
try {
|
|
62
|
+
const user = await this.userService.findById(req.params.id);
|
|
63
|
+
if (!user) return res.status(404).json({ error: 'Not found' });
|
|
64
|
+
res.json(user);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
next(error);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
41
70
|
```
|
|
42
71
|
|
|
43
72
|
### Error Handler
|
|
44
|
-
|
|
45
|
-
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// middleware/errorHandler.ts
|
|
76
|
+
import { Request, Response, NextFunction } from 'express';
|
|
77
|
+
|
|
78
|
+
export class AppError extends Error {
|
|
79
|
+
constructor(
|
|
80
|
+
public statusCode: number,
|
|
81
|
+
message: string,
|
|
82
|
+
public isOperational = true
|
|
83
|
+
) {
|
|
84
|
+
super(message);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function errorHandler(
|
|
89
|
+
err: Error,
|
|
90
|
+
req: Request,
|
|
91
|
+
res: Response,
|
|
92
|
+
next: NextFunction
|
|
93
|
+
) {
|
|
94
|
+
if (err instanceof AppError) {
|
|
95
|
+
return res.status(err.statusCode).json({ error: err.message });
|
|
96
|
+
}
|
|
97
|
+
|
|
46
98
|
console.error(err);
|
|
47
|
-
res.status(500).json({ error: 'Internal
|
|
48
|
-
}
|
|
99
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Validation Middleware
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// middleware/validate.ts
|
|
107
|
+
import { Request, Response, NextFunction } from 'express';
|
|
108
|
+
import { ZodSchema } from 'zod';
|
|
109
|
+
|
|
110
|
+
export function validate(schema: ZodSchema) {
|
|
111
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
112
|
+
const result = schema.safeParse({
|
|
113
|
+
body: req.body,
|
|
114
|
+
query: req.query,
|
|
115
|
+
params: req.params,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!result.success) {
|
|
119
|
+
return res.status(400).json({ errors: result.error.issues });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
next();
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Workflows
|
|
128
|
+
|
|
129
|
+
### API Development Workflow
|
|
130
|
+
|
|
131
|
+
1. Define routes in `routes/index.ts`
|
|
132
|
+
2. Create controller with business logic
|
|
133
|
+
3. Add validation schemas with Zod
|
|
134
|
+
4. Write tests with supertest
|
|
135
|
+
5. Document with OpenAPI/Swagger
|
|
136
|
+
|
|
137
|
+
### Middleware Order
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
1. Security (helmet, cors)
|
|
141
|
+
2. Rate limiting
|
|
142
|
+
3. Body parsing
|
|
143
|
+
4. Logging
|
|
144
|
+
5. Authentication
|
|
145
|
+
6. Routes
|
|
146
|
+
7. 404 handler
|
|
147
|
+
8. Error handler
|
|
49
148
|
```
|
|
50
149
|
|
|
51
150
|
## Best Practices
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
151
|
+
|
|
152
|
+
| Do | Avoid |
|
|
153
|
+
|----|-------|
|
|
154
|
+
| Use async/await with try-catch | Callback patterns |
|
|
155
|
+
| Validate all inputs | Trusting client data |
|
|
156
|
+
| Use typed request/response | `any` types |
|
|
157
|
+
| Centralize error handling | Scattered try-catch |
|
|
158
|
+
| Use dependency injection | Direct imports in controllers |
|
|
159
|
+
|
|
160
|
+
## Project Structure
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
src/
|
|
164
|
+
├── app.ts # Express setup
|
|
165
|
+
├── server.ts # Server entry
|
|
166
|
+
├── config/ # Environment config
|
|
167
|
+
├── controllers/ # Route handlers
|
|
168
|
+
├── middleware/ # Custom middleware
|
|
169
|
+
├── routes/ # Route definitions
|
|
170
|
+
├── services/ # Business logic
|
|
171
|
+
├── utils/ # Helpers
|
|
172
|
+
└── types/ # TypeScript types
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For detailed examples and patterns, see reference files above.
|
|
@@ -1,58 +1,177 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: fastapi
|
|
3
|
-
description: FastAPI
|
|
2
|
+
name: building-fastapi-apis
|
|
3
|
+
description: Builds high-performance FastAPI applications with async/await, Pydantic v2, dependency injection, and SQLAlchemy. Use when creating Python REST APIs, async backends, or microservices.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# FastAPI
|
|
6
|
+
# FastAPI
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
7
9
|
|
|
8
|
-
## Setup
|
|
9
10
|
```python
|
|
10
|
-
from fastapi import FastAPI
|
|
11
|
-
from pydantic import BaseModel
|
|
11
|
+
from fastapi import FastAPI
|
|
12
12
|
|
|
13
13
|
app = FastAPI()
|
|
14
|
+
|
|
15
|
+
@app.get("/health")
|
|
16
|
+
async def health_check():
|
|
17
|
+
return {"status": "ok"}
|
|
18
|
+
|
|
19
|
+
@app.get("/users/{user_id}")
|
|
20
|
+
async def get_user(user_id: int):
|
|
21
|
+
return {"user_id": user_id}
|
|
14
22
|
```
|
|
15
23
|
|
|
16
|
-
##
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
| Feature | Description | Guide |
|
|
27
|
+
|---------|-------------|-------|
|
|
28
|
+
| Routing | Path params, query params, body | [ROUTING.md](ROUTING.md) |
|
|
29
|
+
| Pydantic | Schemas, validation, serialization | [SCHEMAS.md](SCHEMAS.md) |
|
|
30
|
+
| Dependencies | Injection, database sessions | [DEPENDENCIES.md](DEPENDENCIES.md) |
|
|
31
|
+
| Auth | JWT, OAuth2, security utils | [AUTH.md](AUTH.md) |
|
|
32
|
+
| Database | SQLAlchemy async, migrations | [DATABASE.md](DATABASE.md) |
|
|
33
|
+
| Testing | pytest, AsyncClient | [TESTING.md](TESTING.md) |
|
|
34
|
+
|
|
35
|
+
## Common Patterns
|
|
36
|
+
|
|
37
|
+
### Pydantic Schemas
|
|
17
38
|
|
|
18
|
-
### Route with Pydantic
|
|
19
39
|
```python
|
|
40
|
+
from pydantic import BaseModel, EmailStr, Field, field_validator
|
|
41
|
+
|
|
20
42
|
class UserCreate(BaseModel):
|
|
21
|
-
email:
|
|
22
|
-
|
|
43
|
+
email: EmailStr
|
|
44
|
+
name: str = Field(..., min_length=2, max_length=100)
|
|
45
|
+
password: str = Field(..., min_length=8)
|
|
46
|
+
|
|
47
|
+
@field_validator("password")
|
|
48
|
+
@classmethod
|
|
49
|
+
def validate_password(cls, v: str) -> str:
|
|
50
|
+
if not any(c.isupper() for c in v):
|
|
51
|
+
raise ValueError("Must contain uppercase")
|
|
52
|
+
if not any(c.isdigit() for c in v):
|
|
53
|
+
raise ValueError("Must contain digit")
|
|
54
|
+
return v
|
|
23
55
|
|
|
24
|
-
class
|
|
25
|
-
|
|
26
|
-
email: str
|
|
56
|
+
class UserResponse(BaseModel):
|
|
57
|
+
model_config = ConfigDict(from_attributes=True)
|
|
27
58
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
59
|
+
id: UUID
|
|
60
|
+
email: EmailStr
|
|
61
|
+
name: str
|
|
62
|
+
created_at: datetime
|
|
31
63
|
```
|
|
32
64
|
|
|
33
65
|
### Dependency Injection
|
|
66
|
+
|
|
34
67
|
```python
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
from fastapi import Depends
|
|
69
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
70
|
+
|
|
71
|
+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
|
72
|
+
async with async_session_maker() as session:
|
|
73
|
+
yield session
|
|
74
|
+
|
|
75
|
+
async def get_current_user(
|
|
76
|
+
token: str = Depends(oauth2_scheme),
|
|
77
|
+
db: AsyncSession = Depends(get_db),
|
|
78
|
+
) -> User:
|
|
79
|
+
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
|
80
|
+
user = await db.get(User, payload["sub"])
|
|
81
|
+
if not user:
|
|
82
|
+
raise HTTPException(status_code=401)
|
|
83
|
+
return user
|
|
84
|
+
|
|
85
|
+
# Type aliases for cleaner signatures
|
|
86
|
+
DB = Annotated[AsyncSession, Depends(get_db)]
|
|
87
|
+
CurrentUser = Annotated[User, Depends(get_current_user)]
|
|
45
88
|
```
|
|
46
89
|
|
|
47
|
-
###
|
|
90
|
+
### Route with Service Layer
|
|
91
|
+
|
|
48
92
|
```python
|
|
49
|
-
@
|
|
50
|
-
async def
|
|
51
|
-
|
|
93
|
+
@router.get("/", response_model=PaginatedResponse[UserResponse])
|
|
94
|
+
async def list_users(
|
|
95
|
+
db: DB,
|
|
96
|
+
current_user: CurrentUser,
|
|
97
|
+
page: int = Query(1, ge=1),
|
|
98
|
+
limit: int = Query(20, ge=1, le=100),
|
|
99
|
+
):
|
|
100
|
+
service = UserService(db)
|
|
101
|
+
users, total = await service.list(offset=(page - 1) * limit, limit=limit)
|
|
102
|
+
return PaginatedResponse.create(data=users, total=total, page=page, limit=limit)
|
|
103
|
+
|
|
104
|
+
@router.post("/", response_model=UserResponse, status_code=201)
|
|
105
|
+
async def create_user(db: DB, user_in: UserCreate):
|
|
106
|
+
service = UserService(db)
|
|
107
|
+
if await service.get_by_email(user_in.email):
|
|
108
|
+
raise HTTPException(status_code=409, detail="Email exists")
|
|
109
|
+
return await service.create(user_in)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Workflows
|
|
113
|
+
|
|
114
|
+
### API Development
|
|
115
|
+
|
|
116
|
+
1. Define Pydantic schemas for request/response
|
|
117
|
+
2. Create service layer for business logic
|
|
118
|
+
3. Add route with dependency injection
|
|
119
|
+
4. Write tests with pytest-asyncio
|
|
120
|
+
5. Document with OpenAPI (automatic)
|
|
121
|
+
|
|
122
|
+
### Service Pattern
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
class UserService:
|
|
126
|
+
def __init__(self, db: AsyncSession):
|
|
127
|
+
self.db = db
|
|
128
|
+
|
|
129
|
+
async def get_by_id(self, user_id: UUID) -> User | None:
|
|
130
|
+
result = await self.db.execute(
|
|
131
|
+
select(User).where(User.id == user_id)
|
|
132
|
+
)
|
|
133
|
+
return result.scalar_one_or_none()
|
|
134
|
+
|
|
135
|
+
async def create(self, data: UserCreate) -> User:
|
|
136
|
+
user = User(**data.model_dump(), hashed_password=hash_password(data.password))
|
|
137
|
+
self.db.add(user)
|
|
138
|
+
await self.db.commit()
|
|
139
|
+
return user
|
|
52
140
|
```
|
|
53
141
|
|
|
54
142
|
## Best Practices
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
143
|
+
|
|
144
|
+
| Do | Avoid |
|
|
145
|
+
|----|-------|
|
|
146
|
+
| Use async/await everywhere | Sync operations in async code |
|
|
147
|
+
| Validate with Pydantic v2 | Manual validation |
|
|
148
|
+
| Use dependency injection | Direct imports |
|
|
149
|
+
| Handle errors with HTTPException | Generic exceptions |
|
|
150
|
+
| Use type hints | `Any` types |
|
|
151
|
+
|
|
152
|
+
## Project Structure
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
app/
|
|
156
|
+
├── main.py
|
|
157
|
+
├── core/
|
|
158
|
+
│ ├── config.py
|
|
159
|
+
│ ├── security.py
|
|
160
|
+
│ └── deps.py
|
|
161
|
+
├── api/
|
|
162
|
+
│ └── v1/
|
|
163
|
+
│ ├── __init__.py
|
|
164
|
+
│ ├── users.py
|
|
165
|
+
│ └── auth.py
|
|
166
|
+
├── models/
|
|
167
|
+
├── schemas/
|
|
168
|
+
├── services/
|
|
169
|
+
└── db/
|
|
170
|
+
├── base.py
|
|
171
|
+
└── session.py
|
|
172
|
+
tests/
|
|
173
|
+
├── conftest.py
|
|
174
|
+
└── test_users.py
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For detailed examples and patterns, see reference files above.
|