🔌 RESTful APIs
Connect Frontend and Backend Seamlessly
👋 Welcome to RESTful APIs!
REST APIs are the backbone of modern web applications. They allow your frontend to communicate with your backend, enabling data exchange and functionality across different systems.
Understanding APIs is essential for both frontend and backend developers!
🤔 What is a REST API?
REST (Representational State Transfer) is an architectural style for designing networked applications. A REST API is a way for different software applications to communicate over HTTP.
Think of it like a restaurant:
- Client (You): The customer who wants food
- API (Waiter): Takes your order and brings your food
- Server (Kitchen): Prepares the food
The waiter (API) is the interface between you and the kitchen!
🎯 REST Principles
🔗
Client-Server
Separation between frontend and backend
🔄
Stateless
Each request contains all needed information
📦
Cacheable
Responses can be cached for performance
🎨
Uniform Interface
Consistent way to interact with resources
📝 HTTP Methods (CRUD Operations)
GET
Read Data
Retrieve information from the server
GET /api/users
GET /api/users/123
Use for: Fetching data, viewing resources
POST
Create Data
Send new data to the server
POST /api/users
Body: { "name": "John" }
Use for: Creating new resources
PUT
Update Data
Update existing data on the server
PUT /api/users/123
Body: { "name": "Jane" }
Use for: Updating entire resources
DELETE
Delete Data
Remove data from the server
DELETE /api/users/123
Use for: Deleting resources
📊 HTTP Status Codes
2xx Success
- 200 OK: Request succeeded
- 201 Created: Resource created
- 204 No Content: Success, no data returned
4xx Client Errors
- 400 Bad Request: Invalid request
- 401 Unauthorized: Authentication required
- 404 Not Found: Resource doesn't exist
5xx Server Errors
- 500 Internal Server Error: Server problem
- 503 Service Unavailable: Server down
🔧 Building a REST API (Node.js/Express)
Complete CRUD API Example
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
// In-memory data store (use database in production)
let users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];
// GET - Get all users
app.get('/api/users', (req, res) => {
res.json(users);
});
// GET - Get single user
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
// POST - Create new user
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
// Validation
if (!name || !email) {
return res.status(400).json({ error: 'Name and email are required' });
}
const newUser = {
id: users.length + 1,
name,
email
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT - Update user
app.put('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const { name, email } = req.body;
if (name) user.name = name;
if (email) user.email = email;
res.json(user);
});
// DELETE - Delete user
app.delete('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'User not found' });
}
users.splice(index, 1);
res.status(204).send();
});
app.listen(3000, () => {
console.log('API running on http://localhost:3000');
});
💻 Consuming APIs (Frontend)
Using Fetch API (JavaScript)
// GET Request
async function getUsers() {
try {
const response = await fetch('http://localhost:3000/api/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
console.log(users);
} catch (error) {
console.error('Error fetching users:', error);
}
}
// POST Request
async function createUser(userData) {
try {
const response = await fetch('http://localhost:3000/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const newUser = await response.json();
console.log('User created:', newUser);
} catch (error) {
console.error('Error creating user:', error);
}
}
// PUT Request
async function updateUser(id, userData) {
try {
const response = await fetch(`http://localhost:3000/api/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
});
const updatedUser = await response.json();
console.log('User updated:', updatedUser);
} catch (error) {
console.error('Error updating user:', error);
}
}
// DELETE Request
async function deleteUser(id) {
try {
const response = await fetch(`http://localhost:3000/api/users/${id}`, {
method: 'DELETE'
});
if (response.ok) {
console.log('User deleted successfully');
}
} catch (error) {
console.error('Error deleting user:', error);
}
}
// Usage
getUsers();
createUser({ name: 'Alice', email: 'alice@example.com' });
updateUser(1, { name: 'John Updated' });
deleteUser(2);
Using Axios (Popular Library)
// Install: npm install axios
import axios from 'axios';
const API_URL = 'http://localhost:3000/api';
// GET Request
const getUsers = async () => {
try {
const response = await axios.get(`${API_URL}/users`);
console.log(response.data);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
};
// POST Request
const createUser = async (userData) => {
try {
const response = await axios.post(`${API_URL}/users`, userData);
console.log('User created:', response.data);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
};
// PUT Request
const updateUser = async (id, userData) => {
try {
const response = await axios.put(`${API_URL}/users/${id}`, userData);
console.log('User updated:', response.data);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
};
// DELETE Request
const deleteUser = async (id) => {
try {
await axios.delete(`${API_URL}/users/${id}`);
console.log('User deleted');
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
};
🔐 API Authentication
⚠️ Secure Your APIs!
Always implement authentication and authorization for sensitive endpoints.
JWT Authentication Example
// Backend - Generate JWT
const jwt = require('jsonwebtoken');
app.post('/api/login', (req, res) => {
const { email, password } = req.body;
// Verify credentials (check database)
const user = users.find(u => u.email === email);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate token
const token = jwt.sign(
{ userId: user.id, email: user.email },
'your-secret-key',
{ expiresIn: '24h' }
);
res.json({ token });
});
// Middleware to verify token
const authenticate = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, 'your-secret-key');
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
};
// Protected route
app.get('/api/profile', authenticate, (req, res) => {
res.json({ user: req.user });
});
// Frontend - Using token
const login = async (email, password) => {
const response = await fetch('http://localhost:3000/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const { token } = await response.json();
localStorage.setItem('token', token);
};
const getProfile = async () => {
const token = localStorage.getItem('token');
const response = await fetch('http://localhost:3000/api/profile', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const profile = await response.json();
console.log(profile);
};
💡 API Best Practices
REST API Best Practices:
- Use Nouns for Resources: /users, /products (not /getUsers)
- Use HTTP Methods Correctly: GET for reading, POST for creating
- Return Proper Status Codes: 200, 201, 404, 500, etc.
- Version Your API: /api/v1/users
- Use Pagination: For large datasets
- Implement Filtering: /users?role=admin
- Document Your API: Use Swagger/OpenAPI
- Handle Errors Gracefully: Return meaningful error messages
- Use HTTPS: Always in production
- Rate Limiting: Prevent abuse
API Versioning
// Version in URL
app.get('/api/v1/users', (req, res) => { /* ... */ });
app.get('/api/v2/users', (req, res) => { /* ... */ });
// Version in Header
app.get('/api/users', (req, res) => {
const version = req.headers['api-version'];
if (version === '2') {
// V2 logic
} else {
// V1 logic
}
});
Pagination Example
app.get('/api/users', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
const results = {};
if (endIndex < users.length) {
results.next = {
page: page + 1,
limit: limit
};
}
if (startIndex > 0) {
results.previous = {
page: page - 1,
limit: limit
};
}
results.data = users.slice(startIndex, endIndex);
results.total = users.length;
res.json(results);
});
// Usage: GET /api/users?page=2&limit=10
🛠️ API Testing Tools
Postman
Most popular API testing tool
- Test all HTTP methods
- Save requests
- Automated testing
- Team collaboration
Insomnia
Clean, simple interface
- REST and GraphQL
- Environment variables
- Code generation
- Free and open source
Thunder Client
VS Code extension
- Built into VS Code
- Lightweight
- Easy to use
- Collections support
cURL
Command-line tool
- Terminal-based
- Scriptable
- Universal
- Powerful
🎓 Our Training Course
🚀 Master REST APIs!
Build powerful, scalable APIs for your applications
Start Learning →
📖 Related Topics