Overview
Fetch a specific document from a collection by its _id. The endpoint:
- Validates document permissions before returning data
- Applies field-level access controls
- Masks sensitive fields based on user role
- Calculates computed fields
- Logs read access to audit trail (if enabled)
Request
Path Parameters
The name of the collection containing the document
The unique identifier (_id) of the document. Can be MongoDB ObjectId or any string ID.
Bearer token for authentication
Response
The document’s unique identifier
ISO 8601 timestamp when the document was created
ISO 8601 timestamp when the document was last updated
User ID of the user who created the document
All other fields from the document, filtered by field-level permissions and masking rules
Examples
Get by ObjectId
curl -X GET https://api.example.com/users/507f1f77bcf86cd799439011 \
-H "Authorization: Bearer YOUR_TOKEN"
Get by String ID
curl -X GET https://api.example.com/products/SKU-12345 \
-H "Authorization: Bearer YOUR_TOKEN"
Response
{
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "j***@example.com",
"role": "admin",
"status": "active",
"department": "Engineering",
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-15T14:25:00Z",
"created_by": "user_123",
"company_id": "company_456"
}
Note: The email field is masked based on the user’s role permissions.
Implementation Details
MongoDB Query Pattern
The handler uses MongoDB’s findOne operation:
// Convert string ID to ObjectID if applicable
var filter bson.M
objectID, err := primitive.ObjectIDFromHex(id)
if err == nil {
filter = bson.M{"_id": objectID}
} else {
filter = bson.M{"_id": id} // String ID
}
var doc bson.M
err = collection.FindOne(ctx, filter).Decode(&doc)
if err == mongo.ErrNoDocuments {
return ErrNotFound
}
Workflow
- Extract collection and ID from URL path (handlers_crud.go:195-196)
- Validate parameters - collection and ID required (handlers_crud.go:198-205)
- Authenticate request and get auth context (handlers_crud.go:208)
- Validate collection exists in schema (handlers_crud.go:214)
- Fetch document from MongoDB (handlers_crud.go:227)
- Handle not found - return 404 if document doesn’t exist (handlers_crud.go:229)
- Handle invalid ID - return 400 for malformed IDs (handlers_crud.go:236)
- Check RBAC permissions - verify user can read this specific document (handlers_crud.go:249)
- Log audit event if log_reads enabled (handlers_crud.go:258)
- Calculate computed fields - virtual fields not stored in DB (handlers_crud.go:261)
- Apply field policy - remove denied fields (handlers_crud.go:264)
- Apply field masking - mask sensitive data (handlers_crud.go:267)
- Return document with 200 OK (handlers_crud.go:270)
Field-Level Access Control
Fields are filtered based on role policies:
func applyFieldPolicy(authCtx *auth.AuthContext, collection string, doc map[string]interface{}) {
// Get role policies
var denyFields []string
var allowFields []string
for _, role := range authCtx.Roles {
rolePolicy := h.policy.GetRolePolicy(collection, role)
if rolePolicy != nil && rolePolicy.Fields != nil {
denyFields = append(denyFields, rolePolicy.Fields.Deny...)
allowFields = append(allowFields, rolePolicy.Fields.Allow...)
}
}
// If allow list is specified, only keep those fields
if len(allowFields) > 0 {
for field := range doc {
if !contains(allowFields, field) && field != "_id" {
delete(doc, field)
}
}
}
// Remove denied fields
for _, field := range denyFields {
delete(doc, field)
}
}
Field Masking
Sensitive fields are masked based on role permissions:
func applyFieldMasking(authCtx *auth.AuthContext, collection string, doc map[string]interface{}) {
// Get mask configuration from role policies
maskConfig := make(map[string]MaskType)
for _, role := range authCtx.Roles {
rolePolicy := h.policy.GetRolePolicy(collection, role)
if rolePolicy != nil && rolePolicy.Fields != nil {
for field, maskType := range rolePolicy.Fields.Mask {
maskConfig[field] = maskType
}
}
}
// Apply masks
for field, maskType := range maskConfig {
if val, ok := doc[field].(string); ok {
doc[field] = maskValue(val, maskType)
}
}
}
Mask Types:
email: Shows first char and domain (e.g., j***@example.com)
phone: Shows last 4 digits (e.g., ***-***-1234)
partial: Shows first and last char (e.g., j***n)
full: Replaces with ***
Computed Fields
Virtual computed fields are calculated on-the-fly:
# Example schema with computed field
fields:
first_name:
type: string
last_name:
type: string
full_name:
type: string
computed:
expression: "{{first_name}} {{last_name}}"
store: false # Not stored in DB, computed on read
RBAC Permission Check
The system checks if the user can read this specific document:
if !h.canPerformAction(authCtx, collection, config.ActionRead, doc) {
return ErrForbidden
}
Example permission conditions:
- Owner-only:
resource.created_by == user.id
- Tenant isolation:
resource.company_id == user.tenant_id
- Department access:
resource.department in user.departments
- Hierarchical:
resource.owner_id in user.subordinates
Error Responses
400 Bad Request
Returned when ID format is invalid:
{
"error": "Invalid document ID",
"code": "bad_request",
"details": {
"id": "invalid-id-format"
}
}
401 Unauthorized
{
"error": "Authentication required"
}
403 Forbidden
Returned when user doesn’t have permission to read this document:
{
"error": "You don't have permission to perform this action",
"code": "forbidden",
"details": {
"action": "read",
"collection": "users"
}
}
404 Not Found
Returned when document or collection doesn’t exist:
{
"error": "Document not found",
"code": "document_not_found",
"details": {
"collection": "users",
"id": "507f1f77bcf86cd799439011"
}
}
500 Internal Server Error
{
"error": "Failed to retrieve document",
"code": "internal_error",
"details": {
"error": "database connection failed"
}
}
Use Cases
Profile Page
# Get current user's profile
curl -X GET https://api.example.com/users/me \
-H "Authorization: Bearer YOUR_TOKEN"
View Details
# View order details
curl -X GET https://api.example.com/orders/ORD-12345 \
-H "Authorization: Bearer YOUR_TOKEN"
Check Status
# Check task status
curl -X GET https://api.example.com/tasks/task_789 \
-H "Authorization: Bearer YOUR_TOKEN"