meow/Meow/Sources/CatFactsKit/CatFacts.swift

51 lines
1.8 KiB
Swift

//
// CatFacts.swift
// CatFactsKit
//
import Foundation
public struct CatFacts {
let baseURL: URL
let urlSession: URLSession
public init(baseURL: URL, urlSession: URLSession = .shared) {
self.baseURL = baseURL
self.urlSession = urlSession
}
public func getFacts(count: Int? = nil) async throws -> [String] {
let params = count.map { ["count": $0] } ?? [:]
let request = try generateRequest(path: "/", params: params)
let response: FactsResponse = try await decodeRequest(request: request)
return response.data
}
// MARK: - Private functionality
private func generateRequest(path: String, params: [String: CustomStringConvertible] = [:]) throws -> URLRequest {
guard let url = URL(string: path, relativeTo: baseURL) else {
throw CatFactsError.requestError("Couldn't generate URL from path: \(path), baseURL: \(baseURL)")
}
let queryItems = params
.compactMap { URLQueryItem(name: $0, value: $1.description) }
.sorted { a, b in a.name < b.name }
return queryItems.count > 0
? URLRequest(url: url.appending(queryItems: queryItems))
: URLRequest(url: url)
}
private func decodeRequest<T: Decodable>(request: URLRequest) async throws -> T {
let (data, response) = try await urlSession.data(for: request)
guard let response = response as? HTTPURLResponse else {
throw CatFactsError.connectionError("Couldn't get HTTP response from request \(request)")
}
guard response.statusCode < 300 else {
let body = String(data: data, encoding: .utf8)
throw CatFactsError.responseError(response.statusCode, body ?? "unknown error")
}
return try JSONDecoder().decode(T.self, from: data)
}
}