51 lines
1.8 KiB
Swift
51 lines
1.8 KiB
Swift
//
|
|
// CatFacts.swift
|
|
// CatFactsKit
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public struct CatFacts: Sendable {
|
|
public 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)
|
|
}
|
|
}
|