Detailed Explanation of Each Point for REST API Development
1. What is a REST API?
REST (Representational State Transfer) is an architectural style for networked applications using stateless communication.
Key Aspects:
- Works over HTTP/HTTPS.
- Uses resources (users, products) represented by URLs.
- Stateless.
Example:
https://api.example.com/v1/users/123
2. Key Features of REST API
| Feature | Explanation |
|---|---|
| Stateless | Each request contains all data. |
| Client-Server Separation | Frontend and backend are independent. |
| Uniform Interface | Consistent format. |
| Cacheable | Responses can be cached. |
| Layered System | Supports proxies, load balancers. |
3. HTTP Methods in REST API
HTTP methods are verbs for actions on resources.
Common verbs: GET, POST, PUT, PATCH, DELETE
| Method | CRUD | Purpose |
|---|---|---|
| GET | Read | Retrieve Data |
| POST | Create | Add New Data |
| PUT | Update | Full Update |
| PATCH | Update | Partial Update |
| DELETE | Delete | Remove Data |
3.1 GET - Retrieve Data
Purpose
Fetch data (read-only).
Characteristics
- Idempotent.
- Safe.
Example
GET /api/users/123
Response:
{
"id": 123,
"name": "John Doe",
"email": "[email protected]"
}
Best Practices
- ✅ Clear URLs.
- ✅ Avoid sensitive data in URLs.
3.2 POST - Create New Resource
Purpose
Create a new resource.
Example
POST /api/products
Request Body:
{
"name": "Wireless Mouse",
"price": 25.99,
"stock": 100
}
Key Considerations
- ✅ Validate data.
- ✅ Document required fields.
3.3 PUT - Update Resource
Purpose
Replace a resource.
Example
PUT /api/users/123
Request Body:
{
"name": "John Updated",
"email": "[email protected]"
}
Characteristics
- Idempotent.
Best Practices
- ✅ Send all fields.
- ✅ Use for full updates.
3.4 PATCH - Partial Update
Purpose
Modify specific fields.
Example
PATCH /api/products/45
Request Body:
{
"stock": 150
}
Key Considerations
- ✅ Ensure data consistency.
- ✅ Document allowed fields.
3.5 DELETE - Remove Resource
Purpose
Delete a resource.
Example
DELETE /api/orders/78
Characteristics
- Idempotent.
Best Practices
- ✅ Manage related data.
- ✅ Consider soft delete.
4. Less Common HTTP Methods
4.1 HEAD - Retrieve Headers
Purpose
Get headers only.
Example
HEAD /api/products/45
Use Cases
- Check if resource exists.
- Get content length.
4.2 OPTIONS - Describe Operations
Purpose
Ask allowed HTTP methods.
Example
OPTIONS /api/products
Response:
Allow: GET, POST, PUT, DELETE
Use Case
- CORS pre-flight requests.
5. Best Practices for API Design
1️⃣ Use Appropriate HTTP Method
| Action | Method |
|---|---|
| Fetch items | GET |
| Create item | POST |
| Full Update | PUT |
| Partial Update | PATCH |
| Delete item | DELETE |
2️⃣ Follow REST Principles
- Nouns for resources.
- Verbs in HTTP methods.
Example:
GET /users ✔️
POST /users ✔️
DELETE /users/123 ✔️
3️⃣ Return Proper Status Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 404 | Not Found |
| 500 | Server Error |
4️⃣ Secure Your API
- ✅ Use HTTPS.
- ✅ Validate inputs.
- ✅ Use authentication.
- ✅ Implement rate limiting.
5️⃣ Document Everything
Use tools like Swagger or Postman.
Example:
paths:
/users:
get:
summary: Get all users
responses:
200:
description: List of users
6. Quick Recap
| Method | Action | Example |
|---|---|---|
| GET | Read | GET /users/123 |
| POST | Create | POST /products |
| PUT | Update | PUT /users/123 |
| PATCH | Update | PATCH /products/45 |
| DELETE | Remove | DELETE /orders/78 |
| HEAD | Headers | HEAD /products/45 |
| OPTIONS | Allowed | OPTIONS /products |
4. Steps to Develop a REST API
a) Define the Purpose
- What data?
- Who will use it?
b) Choose a Tech Stack
| Language | Framework |
|---|---|
| PHP | Laravel, Slim |
| Node.js | Express.js |
| Python | Flask, FastAPI |
| Java | Spring Boot |
c) Setup Environment
- Install runtime.
- Setup database.
5. Design RESTful Endpoints
Rule: Nouns for resources, verbs in HTTP methods.
| Action | HTTP | Endpoint | Description |
|---|---|---|---|
| List Users | GET | /users |
Retrieve all. |
| Get User | GET | /users/{id} |
Retrieve specific. |
| Create User | POST | /users |
Add new. |
| Update User | PUT | /users/{id} |
Update data. |
| Delete User | DELETE | /users/{id} |
Remove. |
6. Implement CRUD
PHP Example:
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
if (isset($_GET['id'])) {
getUser($_GET['id']);
} else {
getAllUsers();
}
break;
case 'POST':
createUser($_POST);
break;
case 'PUT':
parse_str(file_get_contents("php://input"), $_PUT);
updateUser($_GET['id'], $_PUT);
break;
case 'DELETE':
deleteUser($_GET['id']);
break;
}
Complete API Example
Below is a complete working example of a RESTful API with all CRUD operations and proper error handling:
1. Database Structure
CREATE TABLE items (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2. Complete API Implementation (api.php)
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
header("Content-Type: application/json");
http_response_code(500);
echo json_encode(['message' => 'Database Connection Failed', 'error' => $e->getMessage()]);
die();
}
// API Logic
header("Content-Type: application/json");
$method = $_SERVER['REQUEST_METHOD'];
$path = $_SERVER['PATH_INFO'] ?? '';
switch ($method) {
case 'GET':
handleGetRequest($conn, $path);
break;
case 'POST':
handlePostRequest($conn);
break;
case 'PUT':
handlePutRequest($conn, $path);
break;
case 'DELETE':
handleDeleteRequest($conn, $path);
break;
default:
http_response_code(405);
echo json_encode(['message' => 'Method Not Allowed']);
break;
}
function handleGetRequest($conn, $path) {
if (empty($path) || $path === '/') {
getAllItems($conn);
} else {
$id = intval(substr($path, 1));
if ($id > 0) {
getItemById($conn, $id);
} else {
http_response_code(400);
echo json_encode(['message' => 'Invalid ID']);
}
}
}
function getAllItems($conn) {
try {
$stmt = $conn->query("SELECT * FROM items");
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['message' => 'Error fetching items']);
}
}
function getItemById($conn, $id) {
try {
$stmt = $conn->prepare("SELECT * FROM items WHERE id = ?");
$stmt->execute([$id]);
$item = $stmt->fetch(PDO::FETCH_ASSOC);
if ($item) {
echo json_encode($item);
} else {
http_response_code(404);
echo json_encode(['message' => 'Item not found']);
}
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['message' => 'Error fetching item']);
}
}
function handlePostRequest($conn) {
$input = json_decode(file_get_contents('php://input'), true);
if (!validateInput($input)) {
http_response_code(400);
echo json_encode(['message' => 'Invalid input']);
return;
}
try {
$stmt = $conn->prepare("INSERT INTO items (name, email) VALUES (?, ?)");
$stmt->execute([$input['name'], $input['email']]);
http_response_code(201);
echo json_encode([
'message' => 'Item created',
'id' => $conn->lastInsertId()
]);
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['message' => 'Error creating item']);
}
}
function handlePutRequest($conn, $path) {
$id = intval(substr($path, 1));
if ($id <= 0) {
http_response_code(400);
echo json_encode(['message' => 'Invalid ID']);
return;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!validateInput($input)) {
http_response_code(400);
echo json_encode(['message' => 'Invalid input']);
return;
}
try {
$stmt = $conn->prepare("UPDATE items SET name = ?, email = ? WHERE id = ?");
$stmt->execute([$input['name'], $input['email'], $id]);
if ($stmt->rowCount() > 0) {
echo json_encode(['message' => 'Item updated']);
} else {
http_response_code(404);
echo json_encode(['message' => 'Item not found']);
}
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['message' => 'Error updating item']);
}
}
function handleDeleteRequest($conn, $path) {
$id = intval(substr($path, 1));
if ($id <= 0) {
http_response_code(400);
echo json_encode(['message' => 'Invalid ID']);
return;
}
try {
$stmt = $conn->prepare("DELETE FROM items WHERE id = ?");
$stmt->execute([$id]);
if ($stmt->rowCount() > 0) {
echo json_encode(['message' => 'Item deleted']);
} else {
http_response_code(404);
echo json_encode(['message' => 'Item not found']);
}
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['message' => 'Error deleting item']);
}
}
function validateInput($input) {
return isset($input['name'])
&& isset($input['email'])
&& !empty($input['name'])
&& !empty($input['email'])
&& filter_var($input['email'], FILTER_VALIDATE_EMAIL);
}
?>
3. How to Use
Here are examples of how to interact with the API using cURL:
Get All Items
curl -X GET http://your-domain.com/api.php
Get Single Item
curl -X GET http://your-domain.com/api.php/1
Create New Item
curl -X POST http://your-domain.com/api.php \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "[email protected]"
}'
Update Item
curl -X PUT http://your-domain.com/api.php/1 \
-H "Content-Type: application/json" \
-d '{
"name": "John Updated",
"email": "[email protected]"
}'
Delete Item
curl -X DELETE http://your-domain.com/api.php/1
4. Key Features
- ✅ Full CRUD operations
- ✅ PDO for database operations
- ✅ Input validation
- ✅ Proper error handling
- ✅ HTTP status codes
- ✅ JSON responses
- ✅ Prepared statements for security
- Update database credentials
- Create the database table
- Add proper security measures (authentication, rate limiting)
- Add proper logging
- Implement CORS if needed
Complete PHP REST API Example
Here's a comprehensive example of a REST API implementation with database integration:
Features
- PDO Database Connection
- CRUD Operations
- Error Handling
- Input Validation
- RESTful Endpoints
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api.php | Get all items |
| GET | /api.php/{id} | Get specific item |
| POST | /api.php | Create new item |
| PUT | /api.php/{id} | Update item |
| DELETE | /api.php/{id} | Delete item |
Complete Code (api.php)
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
header("Content-Type: application/json");
http_response_code(500);
echo json_encode(['message' => 'Database Connection Failed']);
die();
}
// API Logic Starts Here
header("Content-Type: application/json");
$method = $_SERVER['REQUEST_METHOD'];
$path = $_SERVER['PATH_INFO'] ?? '';
switch ($method) {
case 'GET':
handleGetRequest($conn, $path);
break;
case 'POST':
handlePostRequest($conn);
break;
case 'PUT':
handlePutRequest($conn, $path);
break;
case 'DELETE':
handleDeleteRequest($conn, $path);
break;
default:
http_response_code(405);
echo json_encode(['message' => 'Method Not Allowed']);
break;
}
Testing the API
Use cURL or Postman to test the endpoints:
# Get all items
curl -X GET http://your-domain.com/api.php
# Create new item
curl -X POST http://your-domain.com/api.php \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"[email protected]"}'
# Update item
curl -X PUT http://your-domain.com/api.php/1 \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"[email protected]"}'
# Delete item
curl -X DELETE http://your-domain.com/api.php/1
Key Features Explained
- Database Connection: Uses PDO for secure database operations
- Error Handling: Proper HTTP status codes and error messages
- Input Validation: Validates email and required fields
- Prepared Statements: Prevents SQL injection
- RESTful Design: Follows REST principles for endpoints
- Update database credentials
- Create necessary database tables
- Set proper permissions
- Implement authentication if needed
7. Use Response Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 404 | Not Found |
| 500 | Server Error |
Example:
{
"status": 404,
"message": "User not found"
}
8. Authentication
🔐 What is API Authentication?
Verifying the identity of a client accessing an API.
🚀 Key Methods
1️⃣ API Keys
🔧 How It Works
Unique token in each request.
✅ Example
GET /api/v1/users
Headers:
Authorization: ApiKey xyz1234securetoken
📌 Suitable For
- Internal services.
- Low-security APIs.
⚠️ Limitations
- No identity context.
- Vulnerable to leaks.
2️⃣ JWT (JSON Web Token)
🔧 How It Works
Server generates signed token with claims.
✅ Example
GET /api/v1/orders
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI...
📌 Suitable For
- Microservices.
- Stateless APIs.
🌟 Benefits
- Self-contained.
- Works across environments.
3️⃣ OAuth 2.0
🔧 How It Works
Delegated authorization for third-party access.
✅ Example Flow
App redirects to auth URL:
https://auth.example.com/oauth/authorize
App calls API with:
GET /api/v1/photos
Headers:
Authorization: Bearer access_token_abc123
📌 Suitable For
- Social logins.
- Third-party apps.
🌟 Benefits
- Fine-grained scopes.
- Standardized.
🔎 Comparison
| Method | Security | Stateless? | Identity | Use Case |
|---|---|---|---|---|
| API Keys | Basic | ✅ | ❌ | Internal APIs |
| JWT | Strong | ✅ | ✅ | Microservices |
| OAuth 2.0 | Strong | ✅ | ✅ | Third-party apps |
✅ Choose Method
| Scenario | Method |
|---|---|
| Quick internal APIs | API Key |
| Stateless API | JWT |
| Third-party access | OAuth 2.0 |
🔐 Best Practices
1️⃣ Enforce HTTPS
Encrypt traffic.
2️⃣ Secure Storage
Secure API Keys.
3️⃣ Rotate Secrets
Rotate keys/tokens.
4️⃣ Least Privilege
Grant minimal permissions.
5️⃣ Validate Inputs
Protect against injection.
6️⃣ Monitor Access
Log authentication events.
⚠️ Common Mistakes
| Mistake | Why It’s Risky |
|---|---|
| Exposing API Keys | Unauthorized access. |
| Same key forever | Risk of abuse. |
| Using HTTP | Exposes credentials. |
| Skipping validation | Injection attacks. |
| Excessive permissions | Violates least privilege. |
📣 Conclusion
9. Input Validation
Validate data to prevent SQL Injection.
PHP Example:
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
http_response_code(400);
echo json_encode(["error" => "Invalid email"]);
exit;
}
10. Error Handling
Log errors and return clean messages.
Example:
{
"error": "User not found",
"code": 404
}
PHP Log:
error_log("User not found: ID " . $user_id);
11. Pagination
Paginate large datasets.
Example Query:
GET /users?page=2&limit=10
Example Response:
{
"page": 2,
"total_pages": 5,
"data": [/* User list */]
}
12. Security
Security is a critical aspect of API development. Here are essential security best practices to protect your API from common vulnerabilities.
12.1 Input Validation
Always validate all incoming data to prevent injection attacks.
// Example: Validating 'id' parameter
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false) {
http_response_code(400);
echo json_encode(["error" => "Invalid ID"]);
exit;
}
12.2 Output Encoding
Encode all API responses to prevent cross-site scripting (XSS).
$name = htmlspecialchars($user['name'], ENT_QUOTES, 'UTF-8');
echo json_encode(['name' => $name]);
12.3 Authentication
Use strong authentication mechanisms:
- OAuth 2.0
- JWT (JSON Web Tokens)
- API Keys
// JWT Authentication Example
$jwt = $_SERVER['HTTP_AUTHORIZATION'] ?? null;
if (!$jwt || !validateJWT($jwt)) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
12.4 Rate Limiting
Protect from abuse and DoS attacks:
$ip = $_SERVER['REMOTE_ADDR'];
$rateLimitKey = "rate_limit:$ip";
// Using Redis for tracking
$requests = $redis->incr($rateLimitKey);
$redis->expire($rateLimitKey, 60); // 60 seconds window
if ($requests > 100) {
http_response_code(429);
echo json_encode(['error' => 'Too many requests']);
exit;
}
12.5 HTTPS Enforcement
Always use HTTPS to encrypt data in transit:
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') {
header("Location: https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
exit;
}
12.6 Secure Error Handling
Avoid exposing sensitive information in errors:
try {
// Risky operation
} catch (Exception $e) {
// Log detailed error internally
error_log($e->getMessage());
// Return generic error to client
http_response_code(500);
echo json_encode(['error' => 'An unexpected error occurred']);
}
12.7 Security Checklist
- ✅ Validate all inputs
- ✅ Use HTTPS everywhere
- ✅ Implement proper authentication
- ✅ Add rate limiting
- ✅ Secure error handling
- ✅ Regular security audits
- ✅ Keep dependencies updated
- ✅ Implement logging and monitoring
13. Documentation
Use Swagger or Postman.
Example:
{
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"summary": "Get all users",
"responses": {
"200": {"description": "OK"}
}
}
}
}
}
14. Testing
- Manual: Postman, cURL.
- Automated: PHPUnit, Jest, PyTest.
PHPUnit Example:
public function testGetUsers() {
$response = $this->get('/api/v1/users');
$this->assertEquals(200, $response->status());
}
15. Versioning
Version APIs.
Example:
https://api.example.com/v1/users
16. Deployment
- Cloud (AWS, DigitalOcean).
- Reverse proxy (Nginx, Apache).
Monitor with:
- New Relic
- ELK Stack
17. Frameworks
| Language | Framework |
|---|---|
| PHP | Laravel |
| Python | Django |
| Node.js | Express |
| Java | Spring Boot |
Final Checklist
- ✅ RESTful Naming.
- ✅ Validate Inputs.
- ✅ Status Codes.
- ✅ Document Endpoints.
- ✅ Secure Data.
- ✅ Monitor Performance.
- ✅ Pagination.
HTTP Headers: A Deep Dive
Introduction
HTTP headers ensure efficient communication, strong security, and better user experience in web development.
What are HTTP Headers?
Metadata
Key-value pairs between client and server, providing context.
How to Inspect
1️⃣ Dev Tools
Right-click > Inspect > Network Tab
2️⃣ Curl
curl -I https://example.com
Key Headers
1️⃣ Content-Type
Purpose
Defines data format.
Example
Content-Type: application/json
2️⃣ Accept
Purpose
Client's preferred formats.
Example
Accept: application/json, text/html
3️⃣ Cache-Control
Purpose
Controls caching.
Example
Cache-Control: max-age=3600
Security Headers
1️⃣ HttpOnly
Purpose
Protects cookies from XSS.
Example
Set-Cookie: authToken=secureToken123; HttpOnly
2️⃣ Secure
Purpose
HTTPS-only cookies.
Example
Set-Cookie: session=abc123; Secure
3️⃣ CORS Headers
Purpose
Controls cross-origin access.
Example
Access-Control-Allow-Origin: https://trusted-site.com
Access-Control-Allow-Methods: GET, POST, PUT
4️⃣ X-Frame-Options
Purpose
Clickjacking protection.
Example
X-Frame-Options: DENY
Best Practices
| Best Practice | Why |
|---|---|
| Set Content-Type | Correct parsing |
| Use CORS | Safeguards API |
| HttpOnly + Secure | Enhances security |
| X-Frame-Options | Clickjacking protection |
| Cache wisely | Improves speed |
| Secure Authorization | Protects API |
Quick Reference
| Header | Type | Example | Purpose |
|---|---|---|---|
| Content-Type | Req/Resp | application/json | Data format |
| Accept | Request | application/json | Response format |
| Cache-Control | Response | max-age=3600 | Caching rules |
| Set-Cookie | Response | session=xyz123 | Client data |
| Authorization | Request | Bearer token123 | Auth |
| Access-Control-Allow-Origin | Response | https://your-frontend.com | CORS |
| X-Frame-Options | Response | DENY | Clickjacking |
Conclusion
REST API Caching Strategies
🔥 Why Caching Matters
Caching allows the temporary storage of responses, reducing:
- ✅ Server Load
- ✅ Latency
- ✅ Bandwidth Usage
⚙️ Types of Caching Strategies
1️⃣ Client-Side Caching
🔧 What is it?
Client caches API responses locally.
📂 Key Types
- Browser Caching
- Mobile App Caching
✅ Example: Browser Caching
GET /products
Cache-Control: max-age=3600
Caches response for 1 hour.
🚨 When to Use
- Static data.
- Offline functionality.
2️⃣ Server-Side Caching
🔧 What is it?
API infrastructure caches responses.
📂 Key Types
- Reverse Proxy Cache
- CDN Cache
- API Gateway Cache
✅ Example: CDN Cache
GET https://cdn.example.com/api/products
CDN responds directly.
🚨 When to Use
- Public APIs.
- Read-heavy traffic.
3️⃣ Application/Service Caching
🔧 What is it?
Application caches data internally.
📂 Key Types
- In-Memory Cache
- Database Cache
✅ Example: Redis Cache
$cacheKey = "user_profile_123";
$data = $redis->get($cacheKey);
if (!$data) {
$data = fetchUserProfileFromDB(123);
$redis->set($cacheKey, json_encode($data), 3600); // Cache for 1 hour
}
return $data;
🚨 When to Use
- Frequently accessed data.
- Expensive queries.
4️⃣ HTTP Caching Headers
🔧 What is it?
HTTP headers guide caching.
🔗 Important Headers
- Cache-Control
- ETag
- Last-Modified
✅ Example: Conditional Requests
1. Initial Request:
GET /profile/123
ETag: "v1.0"
2. Later request:
GET /profile/123
If-None-Match: "v1.0"
3. If data unchanged:
304 Not Modified
🚨 When to Use
- Periodically changing data.
- Reducing bandwidth.
📊 Comparison
| Strategy | Stored Where? | Use Case | Benefit |
|---|---|---|---|
| Client-Side | Browser/App | Product Lists | Fastest |
| Server-Side | CDN/Proxy | News Feeds | Global scale |
| Application | API service | User Profiles | App level control |
| HTTP Headers | Everywhere | User Avatars | Flexible |
🎯 Choosing Strategy
| Requirement | Best Fit |
|---|---|
| Speeding up static data | Client-Side Cache |
| Global caching | CDN |
| Speeding up dynamic data | Application Cache |
| Flexible caching | HTTP Headers |
✅ Best Practices
1️⃣ Cache What Makes Sense
Cache frequently accessed data.
2️⃣ Set Expiry Times
Short TTL for fast-changing data.
3️⃣ Invalidate Wisely
Invalidate cache on data changes.
4️⃣ Leverage HTTP Headers
Set Cache-Control, ETag.
5️⃣ Monitor Performance
Log cache hits vs misses.
⚠️ Common Mistakes
| Mistake | Risk |
|---|---|
| Caching Sensitive Data | Data leak |
| No Expiry Set | Stale data |
| Overcaching | Outdated info |
| Not Invalidating | Incorrect data |
📣 Conclusion
Smart caching = Faster, Cheaper, Better APIs