Ответ
Да, реализовывал абстракцию сетевого слоя на основе URLSession с использованием протоколов для гибкости и тестируемости.
Ключевые компоненты:
- Протокол сервиса — определяет контракт для работы с сетью.
- Модель Endpoint — инкапсулирует данные запроса (путь, метод, параметры).
- Конкретная реализация — выполняет запросы и обрабатывает ответы.
// 1. Протокол для инъекции зависимостей и тестирования
protocol NetworkServiceProtocol {
func request<T: Decodable>(_ endpoint: Endpoint) async throws -> T
}
// 2. Модель, описывающая конечную точку API
struct Endpoint {
let path: String
let method: HTTPMethod // GET, POST и т.д.
let parameters: [String: Any]?
let headers: [String: String]?
}
// 3. Реализация с использованием async/await
final class DefaultNetworkService: NetworkServiceProtocol {
private let session: URLSession
private let decoder: JSONDecoder
init(session: URLSession = .shared, decoder: JSONDecoder = JSONDecoder()) {
self.session = session
self.decoder = decoder
}
func request<T: Decodable>(_ endpoint: Endpoint) async throws -> T {
// Построение URLRequest на основе Endpoint
let request = try buildRequest(from: endpoint)
// Выполнение запроса
let (data, response) = try await session.data(for: request)
// Валидация HTTP-ответа
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw NetworkError.invalidServerResponse
}
// Декодирование данных в модель
return try decoder.decode(T.self, from: data)
}
private func buildRequest(from endpoint: Endpoint) throws -> URLRequest { ... }
}
Преимущества такого подхода:
- Тестируемость: Легко подменить
NetworkServiceProtocolмоком в юнит-тестах. - Гибкость: Отделение логики запроса от бизнес-логики.
- Безопасность: Централизованная обработка ошибок сети и декодирования.
- Современность: Использование
async/awaitдля чистого и читаемого асинхронного кода.