WallhavenAPI.swift

2.5 KB · raw

1import Foundation23enum WallhavenError: Error {4  case invalidURL5  case networkError(Error)6  case decodingError(Error)7  case noData8  case apiError(String)9}1011/// Sort order for Wallhaven search results. Maps to the `sorting` query12/// parameter on the public API. `random` returns a fresh batch per page.13enum WallhavenSorting: String {14  case dateAdded = "date_added"15  case toplist16  case random17}1819@MainActor20protocol WallhavenSearching {21  func searchWallpapers(22    query: String, categories: String, purity: String, sorting: WallhavenSorting,23    resolutions: [String], ratios: [String], limit: Int, page: Int24  ) async throws -> ([Wallpaper], Meta?)25}2627class WallhavenAPI: WallhavenSearching {28  private let session: URLSession2930  init(session: URLSession = .shared) {31    self.session = session32  }3334  func searchWallpapers(35    query: String,36    categories: String = "111",37    purity: String = "100",38    sorting: WallhavenSorting = .dateAdded,39    resolutions: [String] = [],40    ratios: [String] = [],41    limit: Int = 24,42    page: Int = 143  ) async throws -> ([Wallpaper], Meta?) {44    var queryItems = [45      URLQueryItem(name: "q", value: query),46      URLQueryItem(name: "categories", value: categories),47      URLQueryItem(name: "purity", value: purity),48      URLQueryItem(name: "sorting", value: sorting.rawValue),49      URLQueryItem(name: "limit", value: String(limit)),50      URLQueryItem(name: "page", value: String(page)),51    ]5253    if !resolutions.isEmpty {54      queryItems.append(55        URLQueryItem(name: "resolutions", value: resolutions.joined(separator: ",")))56    }5758    if !ratios.isEmpty {59      queryItems.append(URLQueryItem(name: "ratios", value: ratios.joined(separator: ",")))60    }6162    return try await performSearch(queryItems: queryItems)63  }6465  private func performSearch(queryItems: [URLQueryItem]) async throws -> ([Wallpaper], Meta?) {66    var urlComponents = URLComponents(67      url: Configuration.baseURL.appendingPathComponent("search"), resolvingAgainstBaseURL: true)!68    urlComponents.queryItems = queryItems6970    let url = urlComponents.url!7172    let (data, response) = try await session.data(from: url)7374    guard let httpResponse = response as? HTTPURLResponse,75      (200...299).contains(httpResponse.statusCode)76    else {77      throw WallhavenError.apiError("Server returned an error")78    }7980    do {81      let decodedResponse = try JSONDecoder().decode(WallhavenResponse.self, from: data)82      return (decodedResponse.data, decodedResponse.meta)83    } catch {84      throw WallhavenError.decodingError(error)85    }86  }87}