В сучасній розробці для фронтенду важливо підтримувати чисту та масштабовану архітектуру для взаємодії з API. Зі зростанням додатків зростає й складність управління API викликами, особливо коли потрібно працювати з кількома кінцевими точками, різноманітними перетвореннями даних і специфічними вимогами до посередників. Шаблон Репозиторію Модульних Посередників надає структурований підхід для вирішення цих проблем, забезпечуючи гнучкість, повторне використання та підтримуваність у взаємодії з API.
Шаблон Репозиторію для API.
Що таке Шаблон Репозиторію Модульних Посередників?
Шаблон Репозиторію Модульних Посередників — це архітектурний дизайн, який організовує виклики API в модульні, багаторазові одиниці з чітким розмежуванням відповідальностей.
Цей шаблон інтегрує функціональність посередників (middleware) безпосередньо в конвеєр викликів API, що дозволяє здійснювати попередню обробку, пост-обробку, обробку помилок та трансформацію відповідей API у послідовний спосіб.
Ключові компоненти
Репозиторій
- Виконує роль централізованого хабу для всіх взаємодій з API.
- Кожен модуль репозиторію відповідає за конкретну функціональність або домен додатку (наприклад,
UserRepository
,ProductRepository
).
Шар Посередників (Middleware)
- Обробляє загальні проблеми, такі як автентифікація, логування, трансформація запитів та валідація відповідей.
- Функції посередників можуть бути зкомбіновані та використовуватись повторно в різних репозиторіях.
API Клієнт
- Забезпечує основні методи для виконання HTTP запитів (наприклад, GET, POST, PUT, DELETE).
- Налаштовується з глобальними параметрами, такими як базова URL, заголовки та перехоплювачі (interceptors).
Шар Хуків (необов'язково)
- Пропонує хуки React для інтеграції функцій репозиторіїв у компоненти з управлінням станом для станів завантаження та помилок.
Реалізація
Налаштування API клієнта
import axios, { AxiosInstance } from 'axios';
const apiClient: AxiosInstance = axios.create({
baseURL: process.env.API_BASE_URL,
timeout: 10000,
});apiClient.interceptors.request.use(
(config) => {
// Додаємо заголовки для автентифікації чи інші глобальні налаштування
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);apiClient.interceptors.response.use(
(response) => response,
(error) => {
// Глобальна обробка помилок
console.error('API Error:', error);
return Promise.reject(error);
}
);export default apiClient;
Створення функцій посередників
export const authMiddleware = async (config: any) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
};
export const logMiddleware = async (config: any) => {
console.log('Request:', config);
return config;
};export const responseTransformer = async (response: any) => {
// Трансформація даних відповіді, якщо це необхідно
return response.data;
};
Побудова шару репозиторіїв
import apiClient from './apiClient';
import { authMiddleware, logMiddleware, responseTransformer } from './middlewares';
export class UserRepository {
static async getUserById(userId: string) {
const config = { url: `/users/${userId}`, method: 'GET' }; // Застосовуємо посередники
const requestConfig = await authMiddleware(config);
const finalConfig = await logMiddleware(requestConfig); const response = await apiClient(finalConfig);
return responseTransformer(response);
} static async createUser(userData: any) {
const config = { url: '/users', method: 'POST', data: userData }; const requestConfig = await authMiddleware(config);
const finalConfig = await logMiddleware(requestConfig); const response = await apiClient(finalConfig);
return responseTransformer(response);
}
}
Інтеграція з React Hooks
import { useState, useCallback } from 'react';
const useRepository = (repositoryMethod: (params: P) => Promise) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null); const execute = useCallback(async (params: P) => {
setLoading(true);
setError(null);
try {
const result = await repositoryMethod(params);
setData(result);
return result;
} catch (err: any) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, [repositoryMethod]); return { data, loading, error, execute };
};export default useRepository;
Використання в компонентах
import React, { useEffect } from 'react';
import { UserRepository } from './repositories/UserRepository';
import useRepository from './hooks/useRepository';
const UserProfile = () => {
const { data: user, loading, error, execute } = useRepository(UserRepository.getUserById); useEffect(() => {
execute('12345'); // Завантажити дані користувача за ID
}, [execute]); if (loading) return
Завантаження...
; if (error) return
Помилка: {error}
; return
Ім'я користувача: {user?.name}
; };export default UserProfile; ``` ## Переваги 1.
**Розділення відповідальностей (Separation of Concerns):** Тримає бізнес-логіку поза компонентами та централізує взаємодії з API.
2. **Повторне використання (Reusability):** Проміжне програмне забезпечення (middleware) та методи репозиторіїв можна використовувати повторно в межах програми.
3. **Масштабованість (Scalability):** Легко додавати нове проміжне програмне забезпечення або репозиторії без впливу на існуючу функціональність.
4. **Тестованість (Testability):** Ізольовані методи репозиторіїв та проміжне програмне забезпечення можна тестувати окремо.
## Висновок
Модульний шаблон репозиторіїв з проміжним програмним забезпеченням є ефективним способом керування API-викликами у фронтенд-застосунках. Інкапсулюючи логіку API в репозиторіях і застосовуючи проміжне програмне забезпечення для загальних задач, можна створювати масштабовані та підтримувані програми. У поєднанні з React-хуками цей підхід безшовно інтегрується в життєвий цикл компонентів, роблячи його потужним рішенням для сучасної фронтенд-розробки.
Перекладено з: [Modular Middleware Repository Pattern for API Calling in Frontend](https://theplainscript.medium.com/modular-middleware-repository-pattern-for-api-calling-in-frontend-922c96a5847b)