HTTP Status Codes — Complete Guide to API Response Statuses
In this tutorial, you will learn about HTTP Status Codes. We cover key concepts, practical examples, and best practices to help you master this topic.
HTTP status codes are three-digit response codes that indicate the result of an API request, classified into five ranges from informational to server errors.
What You'll Learn
- Each status code range and its meaning
- The most common codes for REST APIs
- Choosing the right code for each situation
Why It Matters
Correct status codes are the foundation of API error handling. They tell clients immediately whether a request succeeded, failed, or needs more work.
Status Code Ranges
| Range | Category | Meaning |
|---|---|---|
| 1xx | Informational | Request received, continuing |
| 2xx | Success | Request understood and accepted |
| 3xx | Redirection | Further action needed |
| 4xx | Client Error | Request contains bad data |
| 5xx | Server Error | Server failed to fulfill request |
Common Status Codes
| Code | Name | When to Use |
|---|---|---|
| 200 | OK | Successful GET, PUT, PATCH, DELETE |
| 201 | Created | Successful POST (new resource) |
| 204 | No Content | Successful DELETE or update with no body |
| 301 | Moved Permanently | Resource URL changed |
| 400 | Bad Request | Invalid input, missing fields |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate, version conflict |
| 422 | Unprocessable | Validation errors |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server failure |
| 503 | Service Unavailable | Server overloaded or down |
Code Examples
from flask import jsonify
@app.route('/users/<int:user_id>')
def get_user(user_id):
user = db.get_user(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
if not has_permission(user):
return jsonify({"error": "Access denied"}), 403
return jsonify(user.to_dict()), 200
@app.route('/users', methods=['POST'])
def create_user():
data = request.get_json()
if not data.get('email'):
return jsonify({
"error": "Validation failed",
"details": {"email": "Email is required"}
}), 400
user = db.create_user(data)
return jsonify(user.to_dict()), 201
Common Mistakes
1. Returning 500 for Client Errors
Client mistakes should get 4xx codes, not 500.
2. Using 200 for Created Resources
201 Created is more specific and tells clients the resource was created.
3. Returning 403 Instead of 401
Use 401 when auth is missing; 403 when auth is present but insufficient.
4. Not Using 429 for Rate Limiting
429 tells clients to back off and includes a Retry-After header.
5. Hiding 4xx Behind 200 Wrappers
Don't return 200 with {"status": "error"}. Use the appropriate 4xx code.
Practice Questions
- What does a 201 status code indicate?
- What is the difference between 401 and 403?
- When should you use 204 No Content?
- What status code indicates rate limiting?
- Why is 500 incorrect for validation errors?
Answers:
- The request succeeded and a new resource was created.
- 401 means missing/invalid auth; 403 means authenticated but unauthorized.
- For successful operations that don't return a body (e.g., DELETE).
- 429 Too Many Requests.
- Validation errors are the client's fault (4xx), not the server's (5xx).
Challenge: Create a decision tree for selecting the correct HTTP status code based on the request outcome. Cover at least 10 different scenarios.
FAQ
What's Next
Learn about Error Response Formats like RFC 7807 and JSON:API, then explore Validation Errors.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro