Skip to content

Commit 9d9db03

Browse files
Initial Commit
0 parents  commit 9d9db03

4 files changed

Lines changed: 422 additions & 0 deletions

File tree

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc

Package.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// swift-tools-version: 6.2
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "tcgdex",
8+
platforms: [
9+
.macOS(.v12), // This fixes your session.data error
10+
.iOS(.v15), // Keeps it consistent with modern Swift Concurrency
11+
.watchOS(.v8),
12+
.tvOS(.v15)
13+
],
14+
products: [
15+
.library(
16+
name: "tcgdex",
17+
targets: ["tcgdex"]
18+
),
19+
],
20+
targets: [
21+
.target(
22+
name: "tcgdex"
23+
),
24+
.testTarget(
25+
name: "tcgdexTests",
26+
dependencies: ["tcgdex"]
27+
),
28+
]
29+
)

Sources/tcgdex/TCGDex.swift

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
import Foundation
2+
3+
public enum NetworkError: Error {
4+
case badURL
5+
case invalidResponse
6+
case decodingError
7+
}
8+
9+
public class TCGDex {
10+
11+
private let baseURL = "https://api.tcgdex.net/v2/en"
12+
private let session = URLSession.shared
13+
private let decoder = JSONDecoder()
14+
15+
init() {
16+
decoder.dateDecodingStrategy = .iso8601
17+
}
18+
19+
public func cards() async throws -> [CardBrief] {
20+
return try await fetch("/cards")
21+
}
22+
23+
public func card(id: String) async throws -> CardType? {
24+
return try await fetch("/cards/\(id)")
25+
}
26+
27+
public func set(id: String) async throws -> Set? {
28+
return try await fetch("/sets/\(id)")
29+
}
30+
31+
public func sets() async throws -> [SetBrief] {
32+
return try await fetch("/sets")
33+
}
34+
35+
public func serie(id: String) async throws -> Serie? {
36+
return try await fetch("/series/\(id)")
37+
}
38+
39+
public func series() async throws -> [SerieBrief] {
40+
return try await fetch("/series")
41+
}
42+
43+
44+
private func fetch<T: Decodable>(_ endpoint: String) async throws -> T {
45+
guard let url = URL(string: "\(baseURL)/\(endpoint)") else {
46+
throw NetworkError.badURL
47+
}
48+
49+
let (data, response) = try await session.data(from: url)
50+
51+
guard let httpResponse = response as? HTTPURLResponse,
52+
(200...299).contains(httpResponse.statusCode) else {
53+
throw NetworkError.invalidResponse
54+
}
55+
56+
do {
57+
return try decoder.decode(T.self, from: data)
58+
} catch {
59+
print(error)
60+
61+
throw NetworkError.decodingError
62+
}
63+
}
64+
65+
}
66+
67+
public struct Serie : Codable {
68+
let id: String
69+
let logo: String
70+
let name: String
71+
let sets: [SetBrief]
72+
}
73+
74+
75+
public struct SetBrief: Codable {
76+
public let id: String
77+
public let name: String
78+
public let logo: String?
79+
public let cardCount: SetBriefCardCount
80+
}
81+
82+
public struct SetBriefCardCount : Codable {
83+
let total: Int
84+
let official: Int
85+
}
86+
87+
public struct Legal: Codable {
88+
public let expanded: Bool
89+
public let standard: Bool
90+
}
91+
92+
public struct Set: Codable {
93+
public let cardCount: SetCardCount
94+
public let cards: [CardBrief]
95+
public let id: String
96+
public let logo: String
97+
public let legal: Legal
98+
public let name: String
99+
public let releaseDate: String
100+
public let serie: SerieBrief
101+
public let symbol: String
102+
}
103+
104+
public struct SerieBrief: Codable {
105+
public let id: String
106+
public let name: String
107+
}
108+
109+
public struct SetCardCount : Codable {
110+
let firstEd: Int
111+
let holo: Int
112+
let normal: Int
113+
let official: Int
114+
let reverse: Int
115+
let total: Int
116+
}
117+
118+
public struct CardBrief: Codable {
119+
let id: String
120+
let localId: String
121+
let name: String
122+
let image: String?
123+
}
124+
125+
public enum CardType: Decodable {
126+
case pokemon(PokemonCard)
127+
case trainer(TrainerCard)
128+
case energy(EnergyCard)
129+
130+
enum CodingKeys: String, CodingKey {
131+
case category = "category"
132+
}
133+
134+
public init(from decoder: Decoder) throws {
135+
let container = try decoder.container(keyedBy: CodingKeys.self)
136+
let type = try container.decode(String.self, forKey: .category)
137+
138+
switch type {
139+
case "Pokemon":
140+
let data = try PokemonCard(from: decoder)
141+
self = .pokemon(data)
142+
case "Trainer":
143+
let data = try TrainerCard(from: decoder)
144+
self = .trainer(data)
145+
case "Energy":
146+
let data = try EnergyCard(from: decoder)
147+
self = .energy(data)
148+
default:
149+
throw DecodingError.dataCorruptedError(forKey: .category, in: container, debugDescription: "Unknown type")
150+
}
151+
}
152+
}
153+
154+
public protocol Card {
155+
var id: String {get}
156+
var localId: String {get}
157+
var name: String {get}
158+
var image: String? {get}
159+
var category: String {get}
160+
var illustrator: String? {get}
161+
var rarity: String? {get}
162+
var set: SetBrief {get}
163+
var variants: CardVariants {get}
164+
var boosters: [Booster]? {get}
165+
var pricing: Pricing {get}
166+
var updated: Date {get}
167+
var legal: Legal {get}
168+
}
169+
170+
public struct TrainerCard: Card, Codable {
171+
public let id: String
172+
public let localId: String
173+
public let name: String
174+
public let image: String?
175+
public let category: String
176+
public let illustrator: String?
177+
public let rarity: String?
178+
public let set: SetBrief
179+
public let variants: CardVariants
180+
public let boosters: [Booster]?
181+
public let pricing: Pricing
182+
public let updated: Date
183+
public let legal: Legal
184+
185+
public let effect: String
186+
public let trainerType: String?
187+
}
188+
189+
public struct EnergyCard: Card, Codable {
190+
public let id: String
191+
public let localId: String
192+
public let name: String
193+
public let image: String?
194+
public let category: String
195+
public let illustrator: String?
196+
public let rarity: String?
197+
public let set: SetBrief
198+
public let variants: CardVariants
199+
public let boosters: [Booster]?
200+
public let pricing: Pricing
201+
public let updated: Date
202+
public let legal: Legal
203+
204+
public let effect: String?
205+
public let energyType: String
206+
}
207+
208+
public struct PokemonCard: Card, Codable {
209+
public let id: String
210+
public let localId: String
211+
public let name: String
212+
public let image: String?
213+
public let category: String
214+
public let illustrator: String?
215+
public let rarity: String?
216+
public let set: SetBrief
217+
public let variants: CardVariants
218+
public let boosters: [Booster]?
219+
public let pricing: Pricing
220+
public let updated: Date
221+
public let legal: Legal
222+
223+
public let dexId: [Int]?
224+
public let hp: Int?
225+
public let types: [String]?
226+
public let evolveFrom: String?
227+
public let description: String?
228+
public let level: String?
229+
public let stage: String?
230+
public let suffix: String?
231+
public let item: PokemonCardItem?
232+
}
233+
234+
public struct PokemonCardItem : Codable {
235+
let name: String
236+
let effect: String
237+
}
238+
239+
public struct CardVariants: Codable {
240+
public let normal: Bool
241+
public let reverse: Bool
242+
public let holo: Bool
243+
public let firstEdition: Bool
244+
}
245+
246+
public struct Booster: Codable {
247+
public let id: String
248+
public let name: String
249+
public let logo: String?
250+
public let artworkFront: String?
251+
public let artworkBack: String?
252+
253+
enum CodingKeys: String, CodingKey {
254+
case id
255+
case name
256+
case logo
257+
case artworkFront = "artwork_front"
258+
case artworkBack = "artwork_back"
259+
}
260+
}
261+
262+
public struct Pricing: Codable {
263+
public let tcgplayer: TCGPlayerPricing?
264+
public let cardmarket: CardMarketPricing?
265+
}
266+
267+
public struct TCGPlayerPricing: Codable {
268+
public let updated: Date
269+
public let unit: String
270+
public let normal: TCGPlayerPricingVariants?
271+
public let holofoil: TCGPlayerPricingVariants?
272+
public let reverseholofoil : TCGPlayerPricingVariants?
273+
274+
enum CodingKeys: String, CodingKey {
275+
case updated
276+
case unit
277+
case normal
278+
case holofoil
279+
case reverseholofoil = "reverse-holofoil"
280+
}
281+
}
282+
283+
public struct TCGPlayerPricingVariants: Codable {
284+
public let lowPrice: Double?
285+
public let midPrice: Double?
286+
public let highPrice: Double?
287+
public let marketPrice: Double?
288+
public let directLowPrice: Double?
289+
290+
}
291+
292+
public struct CardMarketPricing: Codable {
293+
public let updated: Date
294+
public let unit: String
295+
public let avg: Double?
296+
public let low: Double?
297+
public let trend: Double?
298+
public let avg1: Double?
299+
public let avg7: Double?
300+
public let avg30: Double?
301+
public let avgHolo: Double?
302+
public let lowHolo: Double?
303+
public let trendHolo: Double?
304+
public let avg1Holo: Double?
305+
public let avg7Holo: Double?
306+
public let avg30Holo: Double?
307+
308+
enum CodingKeys: String, CodingKey {
309+
case updated
310+
case unit
311+
case avg
312+
case low
313+
case trend
314+
case avg1
315+
case avg7
316+
case avg30
317+
case avgHolo = "avg-holo"
318+
case lowHolo = "low-holo"
319+
case trendHolo = "trend-holo"
320+
case avg1Holo = "avg1-holo"
321+
case avg7Holo = "avg7-holo"
322+
case avg30Holo = "avg30-holo"
323+
324+
}
325+
}

0 commit comments

Comments
 (0)