RESTful Principles
🎯 What You'll Learn
- What REST is and why it matters
- REST constraints and principles
- Resource-based URLs
- HTTP methods for CRUD operations
- Status codes for API responses
- Best practices for RESTful APIs
What is REST?
REST (Representational State Transfer) is an architectural style for designing networked applications. It uses HTTP methods to perform CRUD operations on resources.
REST treats everything as a resource (product, user, order) that can be accessed via a unique URL and manipulated using standard HTTP methods.
REST Constraints
1. Client-Server Architecture
Separation of concerns: client handles UI, server handles data and business logic.
2. Stateless
Each request contains all information needed. Server doesn't store client state between requests.
3. Cacheable
Responses must define themselves as cacheable or non-cacheable.
4. Uniform Interface
Consistent way to interact with resources using standard HTTP methods.
5. Layered System
Client can't tell if connected directly to server or through intermediaries (load balancers, proxies).
Resource-Based URLs
URLs should represent resources (nouns), not actions (verbs).
| ❌ Bad (Action-Based) | ✅ Good (Resource-Based) |
|---|---|
/getProducts |
/products |
/createProduct |
/products (POST) |
/updateProduct/123 |
/products/123 (PUT) |
/deleteProduct/123 |
/products/123 (DELETE) |
URL Naming Conventions
- Use nouns:
/products, not/getProducts - Use plurals:
/products, not/product - Use lowercase:
/products, not/Products - Use hyphens:
/order-items, not/orderItems - No trailing slashes:
/products, not/products/
HTTP Methods for CRUD
| Operation | HTTP Method | URL | Description |
|---|---|---|---|
| Create | POST | /products |
Create a new product |
| Read (all) | GET | /products |
Get all products |
| Read (one) | GET | /products/123 |
Get product with ID 123 |
| Update (full) | PUT | /products/123 |
Replace product 123 |
| Update (partial) | PATCH | /products/123 |
Update parts of product 123 |
| Delete | DELETE | /products/123 |
Delete product 123 |
Status Codes
Success Codes (2xx)
| Code | Name | When to Use |
|---|---|---|
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST (resource created) |
| 204 | No Content | Successful DELETE, PUT (no response body) |
Client Error Codes (4xx)
| Code | Name | When to Use |
|---|---|---|
| 400 | Bad Request | Invalid request data |
| 401 | Unauthorized | Not authenticated |
| 403 | Forbidden | Not authorized |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource conflict (duplicate) |
Complete RESTful API Example
// Get all products
GET /api/products
→ 200 OK
[
{ "id": 1, "name": "Laptop", "price": 999.99 },
{ "id": 2, "name": "Mouse", "price": 29.99 }
]
// Get single product
GET /api/products/1
→ 200 OK
{ "id": 1, "name": "Laptop", "price": 999.99 }
// Create product
POST /api/products
{ "name": "Keyboard", "price": 79.99 }
→ 201 Created
Location: /api/products/3
{ "id": 3, "name": "Keyboard", "price": 79.99 }
// Update product (full)
PUT /api/products/3
{ "name": "Mechanical Keyboard", "price": 129.99 }
→ 200 OK or 204 No Content
// Update product (partial)
PATCH /api/products/3
{ "price": 99.99 }
→ 200 OK or 204 No Content
// Delete product
DELETE /api/products/3
→ 204 No Content
Nested Resources
For related resources, use nested URLs (but limit to 2 levels).
// Get all orders for a customer
GET /api/customers/123/orders
// Get specific order for a customer
GET /api/customers/123/orders/456
// Create order for a customer
POST /api/customers/123/orders
// ❌ Too deep (avoid)
GET /api/customers/123/orders/456/items/789
Limit nesting to 2 levels. For deeper relationships, use query parameters or separate endpoints.
Filtering, Sorting, and Pagination
Filtering
GET /api/products?category=electronics
GET /api/products?minPrice=100&maxPrice=500
GET /api/products?inStock=true
Sorting
GET /api/products?sortBy=price
GET /api/products?sortBy=price&sortOrder=desc
GET /api/products?sortBy=name,price
Pagination
GET /api/products?page=1&pageSize=20
GET /api/products?skip=20&take=20
// Response with pagination metadata
{
"data": [...],
"page": 1,
"pageSize": 20,
"totalCount": 100,
"totalPages": 5
}
Best Practices
- Use nouns for resources:
/products, not/getProducts - Use HTTP methods correctly: GET for read, POST for create, etc.
- Return appropriate status codes: 200, 201, 204, 400, 404, etc.
- Use plural nouns:
/products, not/product - Version your API:
/api/v1/products - Use HTTPS: Always in production
- Consistent naming: Use lowercase and hyphens
- Limit nesting: Maximum 2 levels
- Support filtering/sorting/pagination: For collections
- Include Location header: For 201 Created responses
- Use JSON: Default format for APIs
- Document your API: Use Swagger/OpenAPI
RESTful API Checklist
- ✅ Resource-based URLs (nouns, not verbs)
- ✅ Proper HTTP methods (GET, POST, PUT, PATCH, DELETE)
- ✅ Correct status codes (2xx, 4xx, 5xx)
- ✅ Stateless (no server-side sessions)
- ✅ JSON format
- ✅ Pagination for large collections
- ✅ Filtering and sorting support
- ✅ Versioning strategy
- ✅ HTTPS in production
- ✅ API documentation
Key Takeaways
- REST: Architectural style using HTTP for CRUD operations
- Resources: Everything is a resource with a unique URL
- HTTP methods: GET (read), POST (create), PUT (update), DELETE (delete)
- Status codes: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 404 Not Found
- Nouns, not verbs:
/products, not/getProducts - Stateless: Each request is independent
- Consistent naming: Lowercase, plurals, hyphens
- Pagination: For large collections
- Versioning: Plan for API evolution
You now understand RESTful principles! In the next section, we'll explore API Controllers—how to implement RESTful APIs in ASP.NET Core using controllers and attributes.