2026-08-21 14:47:46.324577+08 / restful-api
Resources
Guidelines for business resource modeling, naming, hierarchy, and identifier design in RESTful APIs.
Resources
Model the Business Domain
An API should model the business domain and expose resources that represent meaningful business concepts.
Resources should contain the necessary information required by API consumers while avoiding exposing internal implementation details.
A well-designed resource model provides:
- Clear understanding of the business domain
- Consistent resource representation
- Reduced coupling between clients and services
- Better API evolution capability
APIs should not be designed as simple wrappers around database tables. Business concepts and domain logic should be represented through meaningful resources instead of exposing persistence models directly.
For complex domains, different models may exist depending on the business context. The applicable context should always be clearly defined.
Define Useful Resources
Resources should be designed to cover the majority of client use cases.
A useful resource should:
- Contain enough information for common scenarios
- Avoid unnecessary data exposure
- Provide flexibility through filtering, pagination, or embedding mechanisms
The goal is to provide a balanced resource representation:
- Too little information forces clients to make unnecessary API calls.
- Too much information increases payload size and coupling.
Avoid Actions in Resource URLs
REST APIs should be resource-oriented.
Actions should be represented by HTTP methods rather than verbs in URLs.
Use:
POST /orders
GET /orders/{id}
PUT /orders/{id}
DELETE /orders/{id}
Avoid:
POST /orders/create
POST /orders/{id}/cancel
POST /orders/{id}/approve
The URL should represent a resource, while the HTTP method represents the operation.
Modeling Actions as Resources
When an operation represents a business event or state transition, model it as a resource.
Example:
Instead of:
POST /vehicles/{vehicleId}/lock
Use:
PUT /vehicles/{vehicleId}/doors-lock
{
"lockStatus": "locked"
}
or:
POST /vehicles/{vehicleId}/door-actions
{
"type": "unlock"
}
This approach provides better extensibility because actions can later become persistent resources with:
- timestamps
- audit information
- history queries
- additional metadata
Model Complex Operations as Resources
For complex operations requiring multiple parameters, create dedicated resources.
Example:
Instead of:
POST /vehicles/move
Use:
POST /vehicle-transfers
{
"sourceOrganizationId": "org-a",
"targetOrganizationId": "org-b",
"vehicles": [
"vehicle-1",
"vehicle-2"
]
}
This creates a resource representing the transfer operation and enables:
- Tracking operation status
- Auditing historical operations
- Supporting asynchronous processing
Use Domain-Specific Resource Names
Resource names should represent business concepts.
Good:
/sales-orders
/customers
/payment-transactions
Avoid generic names:
/items
/data
/entities
/objects
Domain-specific names improve:
- API readability
- Developer understanding
- Documentation quality
Use URL-Friendly Resource Identifiers
Resource identifiers used in URLs should contain only URL-safe characters.
Recommended characters:
A-Z
a-z
0-9
---
_
:
.
Avoid identifiers requiring additional encoding.
Example:
Good:
/customers/customer_123
Avoid:
/customers/customer name with spaces
Identify Resources and Sub-Resources Through Path Segments
Resources and sub-resources should be represented using URL path segments.
General structure:
/resources/{resource-id}/sub-resources/{sub-resource-id}
Examples:
/customers/123
/customers/123/addresses
/customers/123/addresses/home
A valid resource path should generally imply that parent resources also exist.
For example:
/customers/123/addresses/home
should imply:
/customers
/customers/123
/customers/123/addresses
Composite identifiers should not use / as separators.
Use UUIDs Only When Necessary
UUIDs are useful for distributed systems where identifiers must be generated independently without coordination.
However, UUIDs have disadvantages:
- Difficult for humans to read and remember
- Less convenient for debugging
- Larger storage and network overhead
- No natural ordering
- Less suitable for user-facing identifiers
Use UUIDs mainly when:
- High-scale distributed ID generation is required
- Multiple systems generate IDs independently
- Collision avoidance is critical
For simple business entities, server-generated identifiers may be preferred.
Regardless of identifier type:
- IDs should be represented as strings
- IDs should remain stable after creation
- IDs should not be reused
Limit Resource Types
APIs should avoid exposing too many unrelated resource types.
A resource type represents a group of closely related resources:
Example:
/customers
/customers/{id}
/customers/{id}/addresses
/addresses
Well-designed APIs typically contain a limited number of resource types.
If an API exposes many unrelated resources, consider splitting the API based on business domains or bounded contexts.
Limit Sub-Resource Nesting Levels
Nested resources should only be used when the lifecycle of the child resource is strongly related to the parent resource.
Recommended:
/customers/{id}/orders/{orderId}
Avoid deeply nested structures:
/customers/{id}/orders/{orderId}/items/{itemId}/details/{detailId}
Deep nesting causes:
- Complex URLs
- Difficult API discovery
- Increased coupling
As a guideline, limit nesting depth to approximately three levels.
Summary
A well-designed REST API should:
- Model business concepts instead of database structures
- Use nouns instead of verbs in URLs
- Represent complex operations as resources
- Use meaningful domain-specific resource names
- Keep identifiers URL-friendly
- Use UUIDs only when required
- Avoid excessive resource types
- Avoid deep resource nesting
The goal is to create APIs that are predictable, understandable, extensible, and easy for clients to consume.