-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathAppStoreSearchService.swift
61 lines (52 loc) · 1.87 KB
/
AppStoreSearchService.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import Foundation
import BuildSettingsKit
struct AppStoreLookupResponse: Decodable {
let results: [AppStoreInfo]
struct AppStoreInfo: Decodable {
let trackName: String
let trackId: Int
let trackViewUrl: String
let version: String
let releaseNotes: String
let minimumOsVersion: String
let currentVersionReleaseDate: Date
func currentVersionHasBeenReleased(for days: Int) -> Bool {
guard let daysElapsed = Calendar.current.dateComponents([.day], from: currentVersionReleaseDate, to: Date.now).day else {
return false
}
return daysElapsed > days
}
}
}
protocol AppStoreSearchProtocol {
var appID: String { get }
func lookup() async throws -> AppStoreLookupResponse
}
final class AppStoreSearchService: AppStoreSearchProtocol {
private(set) var appID: String
init(appID: String = BuildSettings.current.itunesAppID) {
self.appID = appID
}
func lookup() async throws -> AppStoreLookupResponse {
guard let url = URL(string: "https://itunes.apple.com/lookup?id=\(appID)") else {
throw AppStoreSearchError.invalidURL
}
let (data, response) = try await URLSession.shared.data(from: url)
try validate(response: response)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(AppStoreLookupResponse.self, from: data)
}
private func validate(response: URLResponse) throws {
guard let response = response as? HTTPURLResponse else {
return
}
guard (200..<400).contains(response.statusCode) else {
throw AppStoreSearchError.unacceptableStatusCode(response.statusCode)
}
}
}
enum AppStoreSearchError: Error {
case invalidURL
case unacceptableStatusCode(_ statusCode: Int?)
}