1import Foundation23enum WallhavenError: Error {4 case invalidURL5 case networkError(Error)6 case decodingError(Error)7 case noData8 case apiError(String)9}1011class WallhavenAPI {12 private let session: URLSession13 14 init(session: URLSession = .shared) {15 self.session = session16 }17 18 func fetchRandomWallpapers(limit: Int = 1) async throws -> [Wallpaper] {19 let queryItems = [20 URLQueryItem(name: "sorting", value: "random"),21 URLQueryItem(name: "limit", value: String(limit))22 ]23 let (data, _) = try await performSearch(queryItems: queryItems)24 return data25 }26 27 func searchWallpapers(28 query: String,29 categories: String = "111",30 purity: String = "100",31 resolutions: [String] = [],32 ratios: [String] = [],33 limit: Int = 24,34 page: Int = 135 ) async throws -> ([Wallpaper], Meta?) {36 var queryItems = [37 URLQueryItem(name: "q", value: query),38 URLQueryItem(name: "categories", value: categories),39 URLQueryItem(name: "purity", value: purity),40 URLQueryItem(name: "sorting", value: "date_added"),41 URLQueryItem(name: "limit", value: String(limit)),42 URLQueryItem(name: "page", value: String(page))43 ]44 45 if !resolutions.isEmpty {46 queryItems.append(URLQueryItem(name: "resolutions", value: resolutions.joined(separator: ",")))47 }48 49 if !ratios.isEmpty {50 queryItems.append(URLQueryItem(name: "ratios", value: ratios.joined(separator: ",")))51 }52 53 return try await performSearch(queryItems: queryItems)54 }55 56 private func performSearch(queryItems: [URLQueryItem]) async throws -> ([Wallpaper], Meta?) {57 var urlComponents = URLComponents(url: Configuration.baseURL.appendingPathComponent("search"), resolvingAgainstBaseURL: true)!58 urlComponents.queryItems = queryItems59 60 guard let url = urlComponents.url else {61 throw WallhavenError.invalidURL62 }63 64 let (data, response) = try await session.data(from: url)65 66 guard let httpResponse = response as? HTTPURLResponse, 67 (200...299).contains(httpResponse.statusCode) else {68 throw WallhavenError.apiError("Server returned an error")69 }70 71 do {72 let decodedResponse = try JSONDecoder().decode(WallhavenResponse.self, from: data)73 return (decodedResponse.data, decodedResponse.meta)74 } catch {75 throw WallhavenError.decodingError(error)76 }77 }78}