64 lines
1.7 KiB
Markdown
64 lines
1.7 KiB
Markdown
# API Endpoint
|
|
|
|
**Task:** "Add an endpoint that returns a user by id."
|
|
|
|
## Without Ponytail
|
|
|
|
```
|
|
app/
|
|
├── controllers/user_controller.py
|
|
├── services/user_service.py
|
|
├── repositories/user_repository.py
|
|
├── schemas/user_schemas.py
|
|
└── exceptions/user_exceptions.py
|
|
```
|
|
|
|
```python
|
|
# schemas/user_schemas.py
|
|
class UserResponseDTO(BaseModel):
|
|
id: int
|
|
name: str
|
|
email: str
|
|
|
|
# repositories/user_repository.py
|
|
class UserRepository:
|
|
def __init__(self, db: Session):
|
|
self.db = db
|
|
def find_by_id(self, user_id: int) -> User | None:
|
|
return self.db.get(User, user_id)
|
|
|
|
# services/user_service.py
|
|
class UserService:
|
|
def __init__(self, repo: UserRepository):
|
|
self.repo = repo
|
|
def get_user(self, user_id: int) -> User:
|
|
user = self.repo.find_by_id(user_id)
|
|
if user is None:
|
|
raise UserNotFoundError(user_id)
|
|
return user
|
|
|
|
# controllers/user_controller.py
|
|
@router.get("/users/{user_id}", response_model=UserResponseDTO)
|
|
def get_user(user_id: int, service: UserService = Depends(get_user_service)):
|
|
try:
|
|
return service.get_user(user_id)
|
|
except UserNotFoundError:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
```
|
|
|
|
Five files, three classes, a custom exception, and a dependency-injection chain — wrapping one database call.
|
|
|
|
## With Ponytail
|
|
|
|
```python
|
|
# ponytail: it's one query
|
|
@app.get("/users/{user_id}")
|
|
def get_user(user_id: int, db: Session = Depends(get_db)):
|
|
user = db.get(User, user_id)
|
|
if not user:
|
|
raise HTTPException(404)
|
|
return user
|
|
```
|
|
|
|
**5 files → 5 lines.** Layers earn their place when there are two implementations, not before. Add the service layer when a second caller shows up — if it ever does.
|