Error Responses
This comprehensive guide covers all error responses in the Blog API, including status codes, error formats, troubleshooting steps, and best practices for error handling.
Error Response Format
The API uses consistent JSON error responses with the following structure:
Standard Error Response
{
"code": "ErrorCode",
"message": "Human-readable error description"
}
Validation Error Response
{
"code": "ValidationError",
"errors": {
"fieldName": {
"type": "field",
"value": "invalid-value",
"msg": "Specific field error message",
"path": "fieldName",
"location": "body"
}
}
}
HTTP Status Codes
2xx Success Codes
200
OK
Successful GET, POST (non-creation), PUT requests
201
Created
Successful resource creation (POST)
204
No Content
Successful DELETE requests
4xx Client Error Codes
400 Bad Request
Usage: Invalid request data, validation failures, business logic violations
Common Error Codes:
ValidationError
: Input validation failedBadRequest
: General bad request (e.g., already liked post)
Examples:
Validation Error:
{
"code": "ValidationError",
"errors": {
"email": {
"type": "field",
"value": "invalid-email",
"msg": "Invalid email address",
"path": "email",
"location": "body"
},
"password": {
"type": "field",
"value": "short",
"msg": "Password must be at least 8 characters long",
"path": "password",
"location": "body"
}
}
}
Business Logic Error:
{
"code": "BadRequest",
"message": "You already liked this blog"
}
Troubleshooting:
Validate all required fields are provided
Check field formats (email, URLs, etc.)
Verify field length constraints
Review business logic constraints
401 Unauthorized
Usage: Authentication issues - missing, invalid, or expired tokens
Error Code: AuthenticationError
Common Scenarios:
Missing Authorization header
Invalid JWT token format
Expired access token
Invalid refresh token
Examples:
Missing Token:
{
"code": "AuthenticationError",
"message": "Access denied, no token provided"
}
Expired Token:
{
"code": "AuthenticationError",
"message": "Token has expired"
}
Invalid Token:
{
"code": "AuthenticationError",
"message": "Invalid token"
}
Troubleshooting:
Ensure Authorization header is included:
Authorization: Bearer <token>
Check if access token has expired - try refreshing
Verify token format is valid JWT
Re-authenticate if refresh token is also expired
Code Example:
const handleAuthError = async (response) => {
if (response.status === 401) {
try {
// Try to refresh token
const newToken = await refreshAccessToken();
// Retry original request with new token
return retryRequest(newToken);
} catch (refreshError) {
// Refresh failed, redirect to login
redirectToLogin();
}
}
};
403 Forbidden
Usage: Authorization issues - insufficient permissions
Error Code: AuthorizationError
Common Scenarios:
User role insufficient for action (regular user trying admin operations)
Attempting to access/modify resources belonging to other users
Admin registration with non-whitelisted email
Examples:
Insufficient Role:
{
"code": "AuthorizationError",
"message": "Access denied, insufficient permissions"
}
Admin Registration Denied:
{
"code": "AuthorizationError",
"message": "You cannot register as an admin"
}
Resource Access Denied:
{
"code": "AuthorizationError",
"message": "You can only delete your own comments"
}
Troubleshooting:
Check user role requirements for the endpoint
Verify user owns the resource they're trying to modify
Confirm admin email is whitelisted for admin registration
Review API documentation for required permissions
404 Not Found
Usage: Requested resource doesn't exist
Error Code: NotFound
Common Scenarios:
Blog post with given ID/slug doesn't exist
User with given ID doesn't exist
Comment with given ID doesn't exist
Invalid endpoint URL
Examples:
Resource Not Found:
{
"code": "NotFound",
"message": "Blog not found"
}
User Not Found:
{
"code": "NotFound",
"message": "User not found"
}
Troubleshooting:
Verify the resource ID/slug is correct
Check if resource was deleted
Ensure endpoint URL is correct
Confirm resource is accessible with current user permissions
413 Payload Too Large
Usage: Uploaded file exceeds size limits
Error Code: ValidationError
Scenarios:
Blog banner image larger than 2MB
Request body too large
Example:
{
"code": "ValidationError",
"message": "File size must be less than 2MB"
}
Troubleshooting:
Compress images before upload
Check file size limits in documentation
Use appropriate image formats (PNG, JPG, WebP)
Consider image optimization tools
429 Too Many Requests
Usage: Rate limit exceeded
Headers: Includes rate limit information
RateLimit-Limit
: Total requests allowedRateLimit-Remaining
: Requests remaining in current windowRateLimit-Reset
: Seconds until limit resetsRetry-After
: Seconds to wait before retrying
Example Response:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 60
RateLimit-Remaining: 0
RateLimit-Reset: 45
Retry-After: 45
Content-Type: application/json
{
"error": "You can only make 60 requests every minute."
}
Troubleshooting:
Implement request rate limiting in client
Use exponential backoff for retries
Check rate limit headers to understand limits
Consider caching responses to reduce API calls
5xx Server Error Codes
500 Internal Server Error
Usage: Unexpected server errors
Error Code: ServerError
Example:
{
"code": "ServerError",
"message": "Internal server error"
}
Troubleshooting:
Retry the request after a brief delay
Check API status page for known issues
Contact support if error persists
Implement proper error logging in your application
Error Handling Best Practices
Client-Side Error Handling
class APIClient {
async makeRequest(url, options = {}) {
try {
const response = await fetch(url, {
...options,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.accessToken}`,
...options.headers,
},
});
if (!response.ok) {
await this.handleError(response);
}
return await response.json();
} catch (error) {
console.error("API Request failed:", error);
throw error;
}
}
async handleError(response) {
const status = response.status;
let errorData;
try {
errorData = await response.json();
} catch {
errorData = { message: "Unknown error occurred" };
}
switch (status) {
case 400:
if (errorData.code === "ValidationError") {
throw new ValidationError(errorData.errors);
}
throw new BadRequestError(errorData.message);
case 401:
// Try to refresh token
if (await this.tryRefreshToken()) {
// Token refreshed, caller should retry
throw new TokenRefreshedError();
}
throw new AuthenticationError(errorData.message);
case 403:
throw new AuthorizationError(errorData.message);
case 404:
throw new NotFoundError(errorData.message);
case 413:
throw new PayloadTooLargeError(errorData.message);
case 429:
const retryAfter = response.headers.get("Retry-After");
throw new RateLimitError(errorData.message, retryAfter);
case 500:
throw new ServerError(errorData.message);
default:
throw new APIError(`HTTP ${status}: ${errorData.message}`);
}
}
}
// Custom Error Classes
class APIError extends Error {
constructor(message) {
super(message);
this.name = "APIError";
}
}
class ValidationError extends APIError {
constructor(errors) {
super("Validation failed");
this.name = "ValidationError";
this.errors = errors;
}
}
class AuthenticationError extends APIError {
constructor(message) {
super(message);
this.name = "AuthenticationError";
}
}
class RateLimitError extends APIError {
constructor(message, retryAfter) {
super(message);
this.name = "RateLimitError";
this.retryAfter = parseInt(retryAfter) || 60;
}
}
React Error Handling Example
import React, { useState } from "react";
const BlogForm = () => {
const [errors, setErrors] = useState({});
const [loading, setLoading] = useState(false);
const handleSubmit = async (formData) => {
setLoading(true);
setErrors({});
try {
const apiClient = new APIClient();
await apiClient.createBlog(formData);
// Success handling
} catch (error) {
if (error instanceof ValidationError) {
// Handle validation errors
setErrors(error.errors);
} else if (error instanceof AuthenticationError) {
// Redirect to login
redirectToLogin();
} else if (error instanceof RateLimitError) {
// Show rate limit message
setErrors({
general: `Rate limit exceeded. Try again in ${error.retryAfter} seconds.`,
});
} else {
// General error handling
setErrors({
general: error.message || "An unexpected error occurred",
});
}
}
setLoading(false);
};
return (
<form onSubmit={handleSubmit}>
{errors.general && <div className="error-banner">{errors.general}</div>}
<input type="text" name="title" className={errors.title ? "error" : ""} />
{errors.title && <span className="field-error">{errors.title.msg}</span>}
{/* Other form fields... */}
</form>
);
};
Retry Logic with Exponential Backoff
class RetryableAPIClient extends APIClient {
async makeRequestWithRetry(url, options = {}, maxRetries = 3) {
let lastError;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await this.makeRequest(url, options);
} catch (error) {
lastError = error;
// Don't retry client errors (4xx) except 429
if (error.status >= 400 && error.status < 500 && error.status !== 429) {
throw error;
}
// Don't retry on last attempt
if (attempt === maxRetries) {
throw error;
}
// Calculate delay with exponential backoff
const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
// Add jitter to prevent thundering herd
const jitter = Math.random() * 1000;
await new Promise((resolve) => setTimeout(resolve, delay + jitter));
}
}
throw lastError;
}
}
Error Code Reference
Authentication Errors (AuthenticationError
)
AuthenticationError
)"Access denied, no token provided"
Missing Authorization header
Add Bearer token to request
"Invalid token"
Malformed JWT
Check token format and generation
"Token has expired"
Expired access token
Refresh token or re-authenticate
"Invalid refresh token"
Expired/invalid refresh token
Re-authenticate user
Authorization Errors (AuthorizationError
)
AuthorizationError
)"Access denied, insufficient permissions"
User role insufficient
Check role requirements
"You cannot register as an admin"
Non-whitelisted admin registration
Use whitelisted email or register as user
"You can only delete your own comments"
Trying to delete others' content
Verify resource ownership
Validation Errors (ValidationError
)
ValidationError
)"Invalid email address"
Use valid email format
password
"Password must be at least 8 characters long"
Increase password length
title
"Title is required"
Provide blog title
content
"Content is required"
Provide blog content
banner_image
"File size must be less than 2MB"
Compress image file
Business Logic Errors (BadRequest
)
BadRequest
)"You already liked this blog"
Duplicate like attempt
Check like status before liking
"Like not found"
Trying to unlike non-liked post
Verify post is liked
"Blog not found"
Invalid blog ID/slug
Check blog exists
Testing Error Scenarios
// Test suite for error handling
describe("API Error Handling", () => {
test("handles validation errors", async () => {
const invalidData = { email: "invalid", password: "123" };
try {
await apiClient.register(invalidData);
} catch (error) {
expect(error).toBeInstanceOf(ValidationError);
expect(error.errors.email.msg).toContain("Invalid email");
expect(error.errors.password.msg).toContain("8 characters");
}
});
test("handles authentication errors", async () => {
const expiredToken = "expired.jwt.token";
try {
await apiClient.getCurrentUser(expiredToken);
} catch (error) {
expect(error).toBeInstanceOf(AuthenticationError);
expect(error.message).toContain("expired");
}
});
test("handles rate limiting", async () => {
// Make requests until rate limited
const promises = Array(100)
.fill()
.map(() => apiClient.getBlogs());
try {
await Promise.all(promises);
} catch (error) {
expect(error).toBeInstanceOf(RateLimitError);
expect(error.retryAfter).toBeGreaterThan(0);
}
});
});
Monitoring and Logging
class APIClientWithLogging extends APIClient {
async handleError(response) {
const errorData = await response.json().catch(() => ({}));
// Log error for monitoring
this.logError({
status: response.status,
url: response.url,
method: response.method || "GET",
error: errorData,
timestamp: new Date().toISOString(),
userId: this.getCurrentUserId(),
});
// Continue with normal error handling
await super.handleError(response);
}
logError(errorInfo) {
// Send to logging service
console.error("API Error:", errorInfo);
// Optional: Send to analytics service
if (typeof analytics !== "undefined") {
analytics.track("API Error", errorInfo);
}
}
}
This comprehensive error handling guide ensures robust client-side error management and provides clear troubleshooting paths for common issues encountered when using the Blog API.
Last updated