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:
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:
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:
@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
POSTmethod for all list endpoints - Reason: POST allows complex request bodies with filters and projection
Endpoint Path
- Pattern:
POST /{resource}/list - Examples:
POST /employees/listPOST /merchants/listPOST /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_listparameter - Service builds MongoDB projection dict when
projection_listis provided - Service returns raw dicts for projection, models otherwise
- Controller passes
projection_listto service - Endpoint uses POST method
- Endpoint path follows
/{resource}/listpattern - Documentation includes projection examples
- Tests cover both projection and non-projection scenarios
Example Request/Response
Request with Projection
POST /employees/list
{
"designation": "ASM",
"status": "active",
"skip": 0,
"limit": 10,
"projection_list": ["user_id", "first_name", "last_name", "email"]
}
Response with Projection
[
{
"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
POST /employees/list
{
"designation": "ASM",
"status": "active",
"skip": 0,
"limit": 10
}
Response without Projection
[
{
"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
- Performance: Reduces database I/O and network bandwidth
- Flexibility: Clients request only what they need
- Consistency: Uniform pattern across all list endpoints
- Scalability: Better performance for mobile and low-bandwidth clients
Common Use Cases
Dashboard Widgets
{
"projection_list": ["id", "name", "status", "count"]
}
List Views
{
"projection_list": ["id", "name", "created_at", "status"]
}
Dropdown/Select Options
{
"projection_list": ["id", "name"]
}
Export Operations
{
"projection_list": ["id", "name", "email", "phone", "status", "created_at"]
}
Anti-Patterns (DO NOT DO)
❌ Don't use GET with query parameters for complex filters
# BAD
@router.get("/list")
async def list_resources(
filter1: str = None,
filter2: str = None,
# ... many parameters
):
❌ Don't ignore projection in service layer
# 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
# 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:
- Create new POST endpoint with projection support
- Keep GET endpoint for backward compatibility (if needed)
- Update documentation to recommend POST endpoint
- Deprecate GET endpoint in next major version
- Remove GET endpoint after deprecation period
Testing Requirements
Every list endpoint must have tests for:
- Full response (no projection)
- Partial projection (subset of fields)
- Single field projection
- Invalid field projection (non-existent fields)
- Empty projection list (should return full response)
- Pagination with projection
- Filters with projection
Documentation Requirements
API documentation must include:
- Request schema with projection_list field
- Example requests with and without projection
- Example responses for both scenarios
- List of commonly used field combinations
- Performance recommendations
Last Updated: December 2024
Applies To: All microservices (SCM, POS, Auth, etc.)
Status: MANDATORY for all new list endpoints