API Response Format
Standard response patterns across all ZoneVast services. Understand how success and error responses are structured in both Django and NestJS services.
API Response Format
ZoneVast services are built with two frameworks — Django REST Framework (Python) and NestJS (TypeScript). Each has its own response conventions. This page documents what to expect from each.
Success Responses
Single Object
Django DRF — returns the serializer data directly:
{
"id": 1,
"username": "my-project",
"title": "My Project",
"owner_id": 42
}
NestJS — some services wrap in an envelope, others return raw:
// Envelope pattern (wrapping response)
{
"success": true,
"message": "Resource retrieved successfully",
"data": { "id": "uuid", "phone": "+966500000000" }
}
// Raw pattern (direct return)
{
"user": { "id": "uuid", "phone": "+966500000000" }
}
Tip: Do not assume a consistent envelope across all services. Check each service's documentation for its specific pattern.
List with Pagination
When an endpoint returns a list, it includes pagination metadata. See Pagination for the full specification.
Operation Result
For write operations (create, update, delete), the response shape varies:
// Django DRF — returns the created/updated object
{ "id": 1, "title": "Created", "status": "active" }
// NestJS — may return a message-only response
{ "message": "Password updated successfully" }
// NestJS — or include the resource
{ "success": true, "message": "Created", "data": { ... } }
Auth Token Responses
Django (zv-auth-service):
{
"access": "eyJhbGciOiJIUzI1NiIs...",
"refresh": "eyJhbGciOiJIUzI1NiIs..."
}
NestJS (zv-flex-auth-service):
{
"user": { "id": "uuid", "phone": "+966500000000" },
"tokens": {
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}
}
Note: Notice the naming difference — Django uses
access/refresh, NestJS usesaccessToken/refreshToken.
Response Headers
Common Headers
|| Header | Present | Description |
||--------|---------|-------------|
|| Content-Type | Always | application/json |
|| X-RateLimit-Limit | When rate-limited | Maximum requests allowed |
|| X-RateLimit-Remaining | When rate-limited | Requests remaining in window |
|| Retry-After | On 429 responses | Seconds until you can retry |
Framework-Specific Details
Django REST Framework
- Default renderer:
JSONRenderer - No custom response wrapper at the framework level
- ViewSet CRUD operations return serializer data directly
- Some manual views wrap responses in
{"data": ...} - No standard
successfield — rely on HTTP status codes
NestJS
- Uses
ValidationPipewithwhitelist: true— unknown fields are silently stripped - Some services use a global exception filter that adds
timestampto errors - Some services wrap responses in
{ success, message, data }envelope - Others return the object directly from the controller
Normalization Tips
When building a client that works across both frameworks:
- Check HTTP status codes first — 2xx means success, 4xx/5xx means error
- Don't assume an envelope — parse the response shape dynamically or per-service
- Token fields differ — handle both
access/refreshandaccessToken/refreshToken - Error shapes differ — see Error Responses for both formats
What's Next
- Error Responses — How errors are structured
- Pagination — List response metadata
- Headers & Authentication — Required headers for every request