Spaces:
Running
Running
| # API Development Standards | |
| ## List Endpoint Requirements | |
| **MANDATORY**: All list/fetch endpoints MUST implement projection list support. | |
| ### Standard Pattern | |
| #### 1. Request Schema | |
| Every list request schema must include: | |
| ```python | |
| from typing import Optional, List | |
| from pydantic import BaseModel, Field | |
| class ResourceListRequest(BaseModel): | |
| """Schema for listing resources with filters.""" | |
| # Your filters here | |
| skip: int = Field(0, ge=0, description="Number of records to skip (pagination)") | |
| limit: int = Field(100, ge=1, le=500, description="Maximum number of records to return") | |
| # MANDATORY: Projection list field | |
| projection_list: Optional[List[str]] = Field( | |
| None, | |
| description="List of fields to include in response (e.g., ['id', 'name', 'status'])" | |
| ) | |
| class Config: | |
| json_schema_extra = { | |
| "example": { | |
| "skip": 0, | |
| "limit": 100, | |
| "projection_list": ["id", "name", "status", "created_at"] | |
| } | |
| } | |
| ``` | |
| #### 2. Service Layer | |
| Services must support MongoDB projection: | |
| ```python | |
| from typing import Optional, List, Dict, Any | |
| async def list_resources( | |
| filters: Dict[str, Any], | |
| skip: int = 0, | |
| limit: int = 100, | |
| projection_list: Optional[List[str]] = None | |
| ): | |
| """List resources with optional field projection.""" | |
| # Build query | |
| query = {} | |
| # ... add your filters | |
| # MANDATORY: Build projection dict | |
| projection_dict = None | |
| if projection_list: | |
| projection_dict = {field: 1 for field in projection_list} | |
| projection_dict["_id"] = 0 # Always exclude MongoDB _id | |
| # Query with projection | |
| cursor = collection.find(query, projection_dict).skip(skip).limit(limit) | |
| documents = await cursor.to_list(length=limit) | |
| # MANDATORY: Return raw dict if projection, model otherwise | |
| if projection_list: | |
| return documents # List[Dict] | |
| else: | |
| return [ResponseModel(**doc) for doc in documents] # List[ResponseModel] | |
| ``` | |
| #### 3. Controller Layer | |
| Controllers must pass projection to service: | |
| ```python | |
| @router.post("/list", summary="List resources") | |
| async def list_resources(payload: ResourceListRequest): | |
| """ | |
| List resources with optional filters and field projection. | |
| **Request Body:** | |
| - `skip`: Pagination offset (default: 0) | |
| - `limit`: Page size (default: 100, max: 500) | |
| - `projection_list`: Optional list of fields to include in response | |
| """ | |
| result = await ResourceService.list_resources( | |
| filters=payload.filters, | |
| skip=payload.skip, | |
| limit=payload.limit, | |
| projection_list=payload.projection_list # MANDATORY: Pass projection | |
| ) | |
| # Return result (service handles projection logic) | |
| return result | |
| ``` | |
| ### Endpoint Specifications | |
| #### HTTP Method | |
| - **REQUIRED**: Use `POST` method for all list endpoints | |
| - **Reason**: POST allows complex request bodies with filters and projection | |
| #### Endpoint Path | |
| - **Pattern**: `POST /{resource}/list` | |
| - **Examples**: | |
| - `POST /employees/list` | |
| - `POST /merchants/list` | |
| - `POST /sales/order/list` | |
| #### Response Format | |
| - **With projection**: Returns `List[Dict[str, Any]]` (raw dictionaries) | |
| - **Without projection**: Returns `List[ResponseModel]` (typed Pydantic models) | |
| ### Implementation Checklist | |
| When creating a new list endpoint, ensure: | |
| - [ ] Request schema includes `projection_list: Optional[List[str]]` field | |
| - [ ] Service method accepts `projection_list` parameter | |
| - [ ] Service builds MongoDB projection dict when `projection_list` is provided | |
| - [ ] Service returns raw dicts for projection, models otherwise | |
| - [ ] Controller passes `projection_list` to service | |
| - [ ] Endpoint uses POST method | |
| - [ ] Endpoint path follows `/{resource}/list` pattern | |
| - [ ] Documentation includes projection examples | |
| - [ ] Tests cover both projection and non-projection scenarios | |
| ### Example Request/Response | |
| #### Request with Projection | |
| ```json | |
| POST /employees/list | |
| { | |
| "designation": "ASM", | |
| "status": "active", | |
| "skip": 0, | |
| "limit": 10, | |
| "projection_list": ["user_id", "first_name", "last_name", "email"] | |
| } | |
| ``` | |
| #### Response with Projection | |
| ```json | |
| [ | |
| { | |
| "user_id": "usr_123", | |
| "first_name": "John", | |
| "last_name": "Doe", | |
| "email": "john.doe@example.com" | |
| }, | |
| { | |
| "user_id": "usr_456", | |
| "first_name": "Jane", | |
| "last_name": "Smith", | |
| "email": "jane.smith@example.com" | |
| } | |
| ] | |
| ``` | |
| #### Request without Projection | |
| ```json | |
| POST /employees/list | |
| { | |
| "designation": "ASM", | |
| "status": "active", | |
| "skip": 0, | |
| "limit": 10 | |
| } | |
| ``` | |
| #### Response without Projection | |
| ```json | |
| [ | |
| { | |
| "user_id": "usr_123", | |
| "employee_code": "EMP001", | |
| "first_name": "John", | |
| "last_name": "Doe", | |
| "email": "john.doe@example.com", | |
| "phone": "+919876543210", | |
| "designation": "ASM", | |
| "status": "active", | |
| "manager_id": "usr_789", | |
| "region": "North", | |
| "created_at": "2024-01-15T10:30:00Z", | |
| "updated_at": "2024-01-20T14:45:00Z" | |
| // ... all other fields | |
| } | |
| ] | |
| ``` | |
| ### Benefits | |
| 1. **Performance**: Reduces database I/O and network bandwidth | |
| 2. **Flexibility**: Clients request only what they need | |
| 3. **Consistency**: Uniform pattern across all list endpoints | |
| 4. **Scalability**: Better performance for mobile and low-bandwidth clients | |
| ### Common Use Cases | |
| #### Dashboard Widgets | |
| ```json | |
| { | |
| "projection_list": ["id", "name", "status", "count"] | |
| } | |
| ``` | |
| #### List Views | |
| ```json | |
| { | |
| "projection_list": ["id", "name", "created_at", "status"] | |
| } | |
| ``` | |
| #### Dropdown/Select Options | |
| ```json | |
| { | |
| "projection_list": ["id", "name"] | |
| } | |
| ``` | |
| #### Export Operations | |
| ```json | |
| { | |
| "projection_list": ["id", "name", "email", "phone", "status", "created_at"] | |
| } | |
| ``` | |
| ### Anti-Patterns (DO NOT DO) | |
| ❌ **Don't use GET with query parameters for complex filters** | |
| ```python | |
| # BAD | |
| @router.get("/list") | |
| async def list_resources( | |
| filter1: str = None, | |
| filter2: str = None, | |
| # ... many parameters | |
| ): | |
| ``` | |
| ❌ **Don't ignore projection in service layer** | |
| ```python | |
| # BAD | |
| async def list_resources(projection_list: Optional[List[str]] = None): | |
| # Ignoring projection_list parameter | |
| cursor = collection.find(query) # Missing projection | |
| return [Model(**doc) for doc in documents] # Always returning models | |
| ``` | |
| ❌ **Don't return inconsistent response types** | |
| ```python | |
| # BAD - Always return same type regardless of projection | |
| if projection_list: | |
| return [Model(**doc) for doc in documents] # Should return raw dicts | |
| ``` | |
| ### Migration Guide | |
| For existing GET endpoints without projection: | |
| 1. Create new POST endpoint with projection support | |
| 2. Keep GET endpoint for backward compatibility (if needed) | |
| 3. Update documentation to recommend POST endpoint | |
| 4. Deprecate GET endpoint in next major version | |
| 5. Remove GET endpoint after deprecation period | |
| ### Testing Requirements | |
| Every list endpoint must have tests for: | |
| 1. **Full response** (no projection) | |
| 2. **Partial projection** (subset of fields) | |
| 3. **Single field projection** | |
| 4. **Invalid field projection** (non-existent fields) | |
| 5. **Empty projection list** (should return full response) | |
| 6. **Pagination with projection** | |
| 7. **Filters with projection** | |
| ### Documentation Requirements | |
| API documentation must include: | |
| 1. Request schema with projection_list field | |
| 2. Example requests with and without projection | |
| 3. Example responses for both scenarios | |
| 4. List of commonly used field combinations | |
| 5. Performance recommendations | |
| --- | |
| **Last Updated**: December 2024 | |
| **Applies To**: All microservices (SCM, POS, Auth, etc.) | |
| **Status**: MANDATORY for all new list endpoints | |