|
Getting your Trinity Audio player ready...
|
“`html
APIs: الدليل الشامل لبناء واستهلاك REST و GraphQL APIs مع أمثلة كود عملية في 2026
APIs (Application Programming Interfaces) هي العمود الفقري للتطبيقات الحديثة. بدونها، لا يمكن للتطبيقات التواصل مع بعضها البعض. في هذا الدليل الشامل، ستتعلم كل شيء عن APIs: من REST الأشهر، إلى GraphQL الأحدث، كيفية بناء API احترافي، كيفية استهلاكه، المصادقة والأمان، مع أمثلة كود عملية باستخدام Node.js و Express.
ما هي APIs ولماذا مهمة؟
API (Application Programming Interface) هو مجموعة من القواعد والبروتوكولات التي تسمح للتطبيقات بالتواصل مع بعضها البعض. هو الوسيط الذي يسمح لتطبيقين مختلفين بالتحدث مع بعضهما.
💡 أمثلة على استخدام APIs في الحياة اليومية
- خرائط جوجل: تطبيقات تستخدم API خرائط جوجل
- الدفع الإلكتروني: Stripe, PayPal APIs
- وسائل التواصل: Facebook, Twitter APIs
- الطقس: Weather APIs
- البريد الإلكتروني: SendGrid, Mailgun APIs
أنواع APIs
⚖️ مقارنة شاملة: REST vs GraphQL vs SOAP
REST API: الأشهر والأكثر استخداماً
🌐 ما هو REST API؟
REST (Representational State Transfer) هو نمط معماري لبناء APIs. يستخدم بروتوكول HTTP ويعتمد على الموارد (Resources) والعمليات (Operations).
مبادئ REST:
- Client-Server: فصل الواجهة عن الخادم
- Stateless: كل طلب مستقل
- Cacheable: الاستجابات قابلة للتخزين المؤقت
- Uniform Interface: واجهة موحدة
- Layered System: نظام طبقي
🌐 HTTP Methods في REST
بناء REST API مع Node.js و Express
🛠️ إعداد المشروع
# إنشاء المشروع mkdir my-api cd my-api npm init -y # تثبيت المكتبات npm install express mongoose cors dotenv bcryptjs jsonwebtoken npm install --save-dev nodemon # هيكل المشروع my-api/ ├── src/ │ ├── controllers/ │ ├── models/ │ ├── routes/ │ ├── middleware/ │ ├── config/ │ └── app.js ├── .env ├── package.json └── server.js
🛠️ بناء API كامل
// server.js const express = require('express'); const cors = require('cors'); const mongoose = require('mongoose'); require('dotenv').config(); const app = express(); // Middleware app.use(cors()); app.use(express.json()); // Connect to MongoDB mongoose.connect(process.env.MONGODB_URI) .then(() => console.log('MongoDB connected')) .catch(err => console.error(err)); // Routes app.use('/api/users', require('./routes/users')); app.use('/api/products', require('./routes/products')); // Error handling app.use((err, req, res, next) => { res.status(err.status || 500).json({ error: err.message || 'Internal Server Error' }); }); const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
🛠️ Model (User Model)
// models/User.js const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const userSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Name is required'], trim: true }, email: { type: String, required: [true, 'Email is required'], unique: true, lowercase: true }, password: { type: String, required: [true, 'Password is required'], minlength: 6 }, role: { type: String, enum: ['user', 'admin'], default: 'user' } }, { timestamps: true }); // Hash password before saving userSchema.pre('save', async function(next) { if (!this.isModified('password')) return next(); this.password = await bcrypt.hash(this.password, 10); next(); }); // Compare password method userSchema.methods.comparePassword = async function(candidatePassword) { return await bcrypt.compare(candidatePassword, this.password); }; module.exports = mongoose.model('User', userSchema);
🛠️ Controller (Users Controller)
// controllers/usersController.js const User = require('../models/User'); const jwt = require('jsonwebtoken'); // @desc Register user // @route POST /api/users/register exports.register = async (req, res) => { try { const { name, email, password } = req.body; // Check if user exists const existingUser = await User.findOne({ email }); if (existingUser) { return res.status(400).json({ error: 'User already exists' }); } // Create user const user = await User.create({ name, email, password }); // Generate token const token = jwt.sign( { id: user._id }, process.env.JWT_SECRET, { expiresIn: '30d' } ); res.status(201).json({ success: true, token, user: { id: user._id, name: user.name, email: user.email } }); } catch (error) { res.status(500).json({ error: error.message }); } }; // @desc Login user // @route POST /api/users/login exports.login = async (req, res) => { try { const { email, password } = req.body; // Find user const user = await User.findOne({ email }).select('+password'); if (!user) { return res.status(401).json({ error: 'Invalid credentials' }); } // Check password const isMatch = await user.comparePassword(password); if (!isMatch) { return res.status(401).json({ error: 'Invalid credentials' }); } // Generate token const token = jwt.sign( { id: user._id }, process.env.JWT_SECRET, { expiresIn: '30d' } ); res.json({ success: true, token, user: { id: user._id, name: user.name, email: user.email } }); } catch (error) { res.status(500).json({ error: error.message }); } }; // @desc Get all users // @route GET /api/users exports.getUsers = async (req, res) => { try { const users = await User.find(); res.json({ success: true, data: users }); } catch (error) { res.status(500).json({ error: error.message }); } }; // @desc Get user by ID // @route GET /api/users/:id exports.getUser = async (req, res) => { try { const user = await User.findById(req.params.id); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json({ success: true, data: user }); } catch (error) { res.status(500).json({ error: error.message }); } }; // @desc Update user // @route PUT /api/users/:id exports.updateUser = async (req, res) => { try { const user = await User.findByIdAndUpdate( req.params.id, req.body, { new: true, runValidators: true } ); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json({ success: true, data: user }); } catch (error) { res.status(500).json({ error: error.message }); } }; // @desc Delete user // @route DELETE /api/users/:id exports.deleteUser = async (req, res) => { try { const user = await User.findByIdAndDelete(req.params.id); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json({ success: true, data: {} }); } catch (error) { res.status(500).json({ error: error.message }); } };
🛠️ Routes
// routes/users.js const express = require('express'); const router = express.Router(); const { protect } = require('../middleware/auth'); const { register, login, getUsers, getUser, updateUser, deleteUser } = require('../controllers/usersController'); router.post('/register', register); router.post('/login', login); router.get('/', protect, getUsers); router.get('/:id', protect, getUser); router.put('/:id', protect, updateUser); router.delete('/:id', protect, deleteUser); module.exports = router;
🛠️ Auth Middleware
// middleware/auth.js const jwt = require('jsonwebtoken'); const User = require('../models/User'); exports.protect = async (req, res, next) => { let token; // Check for token if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { token = req.headers.authorization.split(' ')[1]; } if (!token) { return res.status(401).json({ error: 'Not authorized' }); } try { // Verify token const decoded = jwt.verify(token, process.env.JWT_SECRET); // Get user req.user = await User.findById(decoded.id); next(); } catch (error) { res.status(401).json({ error: 'Not authorized' }); } };
استهلاك API من Frontend
🌐 استهلاك API مع Fetch API
// Register User const registerUser = async (name, email, password) => { try { const response = await fetch('http://localhost:5000/api/users/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email, password }) }); const data = await response.json(); if (!response.ok) { throw new Error(data.error); } // Store token localStorage.setItem('token', data.token); return data; } catch (error) { console.error('Error:', error); } }; // Login User const loginUser = async (email, password) => { try { const response = await fetch('http://localhost:5000/api/users/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); const data = await response.json(); if (!response.ok) { throw new Error(data.error); } localStorage.setItem('token', data.token); return data; } catch (error) { console.error('Error:', error); } }; // Get Users (Protected) const getUsers = async () => { try { const token = localStorage.getItem('token'); const response = await fetch('http://localhost:5000/api/users', { headers: { 'Authorization': `Bearer ${token}` } }); const data = await response.json(); return data; } catch (error) { console.error('Error:', error); } };
🌐 استهلاك API مع Axios
// Install Axios npm install axios // Create Axios instance import axios from 'axios'; const api = axios.create({ baseURL: 'http://localhost:5000/api', headers: { 'Content-Type': 'application/json' } }); // Add token interceptor api.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); // API calls export const registerUser = (data) => api.post('/users/register', data); export const loginUser = (data) => api.post('/users/login', data); export const getUsers = () => api.get('/users'); export const getUser = (id) => api.get(`/users/${id}`); export const updateUser = (id, data) => api.put(`/users/${id}`, data); export const deleteUser = (id) => api.delete(`/users/${id}`); // Usage in React component import { getUsers } from './api'; function UsersList() { const [users, setUsers] = useState([]); useEffect(() => { fetchUsers(); }, []); const fetchUsers = async () => { try { const response = await getUsers(); setUsers(response.data.data); } catch (error) { console.error(error); } }; return ( <div> {users.map(user => ( <div key={user.id}>{user.name}</div> ))} </div> ); }
GraphQL: البديل الحديث
🌐 ما هو GraphQL؟
GraphQL هي لغة استعلام للـ APIs طورتها Facebook. تسمح للعميل بطلب بالضبط ما يحتاجه، لا أكثر ولا أقل.
مميزات GraphQL:
- Ask for what you need: لا over-fetching أو under-fetching
- Get what you ask: تحصل بالضبط على ما طلبت
- Single endpoint: endpoint واحد لكل العمليات
- Strong typing: نظام أنواع قوي
- Introspection: يمكن الاستعلام عن الـ API نفسه
🌐 بناء GraphQL API
# Install dependencies
npm install @apollo/server graphql @apollo/server-plugins
