block-employee-directory/EmployeeDirectory/Services/NetworkService.swift
Matt Bruce 4ae060597c added new networkservice for urlrequest
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2025-01-21 11:16:53 -06:00

90 lines
2.9 KiB
Swift

//
// NetworkService.swift
// EmployeeDirectory
//
// Created by Matt Bruce on 1/20/25.
//
import Foundation
public enum NetworkServiceError: Error {
/// The response from the server was invalid (e.g., non-200 status code or malformed URL).
case invalidResponse
/// The url giving is invalid or malformed
case invalidURL
/// The data received was invalid or could not be decoded.
case decodingError(DecodingError)
/// A network-related error occurred.
case networkError(URLError)
/// An unexpected, uncategorized error occurred.
case unknownError(Error)
}
public class NetworkService {
// MARK: - Properties
public static let shared = NetworkService() // Default shared instance
private let session: URLSession
// MARK: - Initializer
/// Public initializer to allow customization
public init(session: URLSession = .shared) {
self.session = session
}
// MARK: - Public Methods
/// Fetches data from a URL and decodes it into a generic Decodable type.
/// - Parameters:
/// - endpoint: The url to fetch data from.
/// - type: The type to decode the data into.
/// - Throws: A `ServiceError` for network, decoding, or unexpected errors.
/// - Returns: The decoded object of the specified type.
public func fetchData<T: Decodable>(from endpoint: String, as type: T.Type) async throws -> T {
//ensure a valid URL
guard let url = URL(string: endpoint) else {
throw NetworkServiceError.invalidURL
}
return try await fetchData(with: URLRequest(url: url), as: type)
}
/// Fetches data using a URLRequest and decodes it into a generic Decodable type.
/// - Parameters:
/// - request: The URLRequest to execute.
/// - type: The type to decode the data into.
/// - Throws: A `NetworkServiceError` for network, decoding, or unexpected errors.
/// - Returns: The decoded object of the specified type.
public func fetchData<T: Decodable>(with request: URLRequest, as type: T.Type) async throws -> T {
do {
// Perform network request
let (data, response) = try await session.data(for: request)
// Validate HTTP response
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw NetworkServiceError.invalidResponse
}
// Decode the response into the specified type
return try JSONDecoder().decode(T.self, from: data)
} catch let urlError as URLError {
throw NetworkServiceError.networkError(urlError)
} catch let decodingError as DecodingError {
throw NetworkServiceError.decodingError(decodingError)
} catch {
throw NetworkServiceError.unknownError(error)
}
}
}