diff --git a/Sources/Internal/Extensions/Client+Properties.swift b/Sources/Internal/Extensions/Client+Properties.swift new file mode 100644 index 0000000..3449f41 --- /dev/null +++ b/Sources/Internal/Extensions/Client+Properties.swift @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +import OpenAPIURLSession + +extension Client { + + // MARK: Constants + + static var live: Client { + get throws { + .init( + serverURL: try Servers.server1(), + configuration: .init(dateTranscoder: ISODateTranscoder()), + transport: URLSessionTransport() + ) + } + } + +} diff --git a/Sources/Internal/Extensions/DateFormatter+Properties.swift b/Sources/Internal/Extensions/DateFormatter+Properties.swift new file mode 100644 index 0000000..b40d382 --- /dev/null +++ b/Sources/Internal/Extensions/DateFormatter+Properties.swift @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +import Foundation + +extension DateFormatter { + + static var isoDateTime: DateFormatter { + let formatter = DateFormatter() + + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" + formatter.timeZone = .init(secondsFromGMT: 0) + + return formatter + } + +} diff --git a/Sources/Internal/Protocols/KeyNameFilter.swift b/Sources/Internal/Protocols/KeyNameFilter.swift new file mode 100644 index 0000000..d5faf61 --- /dev/null +++ b/Sources/Internal/Protocols/KeyNameFilter.swift @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +protocol KeyNameFilter { + + // MARK: Properties + + var key: String? { get } + var name: String? { get } + + // MARK: Initialisers + + init() + init(key: String) + init(name: String) + +} diff --git a/Sources/Internal/Protocols/KeyNameModel.swift b/Sources/Internal/Protocols/KeyNameModel.swift new file mode 100644 index 0000000..4cfeb06 --- /dev/null +++ b/Sources/Internal/Protocols/KeyNameModel.swift @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +protocol KeyNameModel: Sendable { + + // MARK: Properties + + var key: String { get } + var name: String { get } + + // MARK: Initialisers + + init(_ payload: Components.Schemas.Tuple) + +} diff --git a/Sources/Internal/Transcoders/ISODateTranscoder.swift b/Sources/Internal/Transcoders/ISODateTranscoder.swift new file mode 100644 index 0000000..9ae1a3e --- /dev/null +++ b/Sources/Internal/Transcoders/ISODateTranscoder.swift @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +import Foundation +import OpenAPIRuntime + +struct ISODateTranscoder: DateTranscoder { + + // MARK: Properties + private let dateFormatter: DateFormatter = .isoDateTime + + // MARK: Functions + + func encode(_ date: Date) throws -> String { + dateFormatter.string(from: date) + } + + func decode(_ string: String) throws -> Date { + dateFormatter.date(from: string) ?? .init() + } + +} diff --git a/Sources/Public/Errors/AmiiboServiceError.swift b/Sources/Public/Errors/AmiiboServiceError.swift new file mode 100644 index 0000000..4391117 --- /dev/null +++ b/Sources/Public/Errors/AmiiboServiceError.swift @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public enum AmiiboServiceError: Error { + case badRequest + case notAvailable + case notFound + case undocumented(_ statusCode: Int) +} + +// MARK: - Equatable + +extension AmiiboServiceError: Equatable {} diff --git a/Sources/Public/Filters/AmiiboFilter.swift b/Sources/Public/Filters/AmiiboFilter.swift new file mode 100644 index 0000000..b0c7c29 --- /dev/null +++ b/Sources/Public/Filters/AmiiboFilter.swift @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct AmiiboFilter { + + // MARK: Properties + + public let gameCharacter: String? + public let gameSeries: String? + public let identifier: String? + public let name: String? + public let series: String? + public let showGames: Bool? + public let showUsage: Bool? + public let type: String? + + // MARK: Initialisers + + public init( + identifier: String? = nil, + name: String? = nil, + type: String? = nil, + series: String? = nil, + gameCharacter: String? = nil, + gameSeries: String? = nil, + showGames: Bool? = nil, + showUsage: Bool? = nil + ) { + self.gameCharacter = gameCharacter + self.gameSeries = gameSeries + self.identifier = identifier + self.name = name + self.series = series + self.showGames = showGames + self.showUsage = showUsage + self.type = type + } + +} diff --git a/Sources/Public/Filters/AmiiboSeriesFilter.swift b/Sources/Public/Filters/AmiiboSeriesFilter.swift new file mode 100644 index 0000000..c230ce9 --- /dev/null +++ b/Sources/Public/Filters/AmiiboSeriesFilter.swift @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct AmiiboSeriesFilter: KeyNameFilter { + + // MARK: Properties + + public let key: String? + public let name: String? + + // MARK: Initialisers + + public init() { + self.key = nil + self.name = nil + } + + public init(key: String) { + self.key = key + self.name = nil + } + + public init(name: String) { + self.key = nil + self.name = name + } + +} diff --git a/Sources/Public/Filters/AmiiboTypeFilter.swift b/Sources/Public/Filters/AmiiboTypeFilter.swift new file mode 100644 index 0000000..cf48760 --- /dev/null +++ b/Sources/Public/Filters/AmiiboTypeFilter.swift @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct AmiiboTypeFilter: KeyNameFilter { + + // MARK: Properties + + public let key: String? + public let name: String? + + // MARK: Initialisers + + public init() { + self.key = nil + self.name = nil + } + + public init(key: String) { + self.key = key + self.name = nil + } + + public init(name: String) { + self.key = nil + self.name = name + } + +} diff --git a/Sources/Public/Filters/GameCharacterFilter.swift b/Sources/Public/Filters/GameCharacterFilter.swift new file mode 100644 index 0000000..345dac3 --- /dev/null +++ b/Sources/Public/Filters/GameCharacterFilter.swift @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct GameCharacterFilter: KeyNameFilter { + + // MARK: Properties + + public let key: String? + public let name: String? + + // MARK: Initialisers + + public init() { + self.key = nil + self.name = nil + } + + public init(key: String) { + self.key = key + self.name = nil + } + + public init(name: String) { + self.key = nil + self.name = name + } + +} diff --git a/Sources/Public/Filters/GameSeriesFilter.swift b/Sources/Public/Filters/GameSeriesFilter.swift new file mode 100644 index 0000000..060988d --- /dev/null +++ b/Sources/Public/Filters/GameSeriesFilter.swift @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct GameSeriesFilter: KeyNameFilter { + + // MARK: Properties + + public let key: String? + public let name: String? + + // MARK: Initialisers + + public init() { + self.key = nil + self.name = nil + } + + public init(key: String) { + self.key = key + self.name = nil + } + + public init(name: String) { + self.key = nil + self.name = name + } + +} diff --git a/Sources/Public/Models/Amiibo.swift b/Sources/Public/Models/Amiibo.swift new file mode 100644 index 0000000..f53d900 --- /dev/null +++ b/Sources/Public/Models/Amiibo.swift @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +import Foundation + +public struct Amiibo: Sendable { + + // MARK: Properties + + public let gameCharacter: String + public let gameSeries: String + public let head: String + public let image: String + public let name: String + public let platform: Platform? + public let release: Release + public let series: String + public let tail: String + public let type: String + + // MARK: Initialisers + + init(_ payload: Components.Schemas.Amiibo) { + self.gameCharacter = payload.character + self.gameSeries = payload.gameSeries + self.head = payload.head + self.image = payload.image + self.name = payload.name + self.platform = .init( + payload.gamesSwitch, + payload.games3DS, + payload.gamesWiiU + ) + self.release = .init(payload.release) + self.series = payload.amiiboSeries + self.tail = payload.tail + self.type = payload._type + } + + // MARK: Computed + + public var identifier: String { + head + tail + } + + public var imageURL: URL? { + .init(string: image) + } + +} diff --git a/Sources/Public/Models/Amiibo/Amiibo+Game.swift b/Sources/Public/Models/Amiibo/Amiibo+Game.swift new file mode 100644 index 0000000..a820c11 --- /dev/null +++ b/Sources/Public/Models/Amiibo/Amiibo+Game.swift @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +extension Amiibo { + public struct Game: Sendable { + + // MARK: Properties + + public let identifiers: [String] + public let name: String + public let usages: [Usage]? + + // MARK: Initialisers + + init(_ payload: Components.Schemas.AmiiboGame) { + self.identifiers = payload.gameID + self.name = payload.gameName + self.usages = { + guard let usages = payload.amiiboUsage else { + return nil + } + + return usages.map { .init($0) } + }() + } + + } +} diff --git a/Sources/Public/Models/Amiibo/Amiibo+Platform.swift b/Sources/Public/Models/Amiibo/Amiibo+Platform.swift new file mode 100644 index 0000000..36c9ec0 --- /dev/null +++ b/Sources/Public/Models/Amiibo/Amiibo+Platform.swift @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +extension Amiibo { + public struct Platform: Sendable { + + // MARK: Properties + + public let `switch`: [Game] + public let threeDS: [Game] + public let wiiU: [Game] + + // MARK: Initialisers + + init?( + _ `switch`: [Components.Schemas.AmiiboGame]?, + _ threeDS: [Components.Schemas.AmiiboGame]?, + _ wiiU: [Components.Schemas.AmiiboGame]? + ) { + guard (`switch` != nil && `switch`?.isEmpty == false) + || (threeDS != nil && threeDS?.isEmpty == false) + || (wiiU != nil && wiiU?.isEmpty == false) + else { + return nil + } + + self.switch = { + guard let `switch` else { return [] } + return `switch`.map { .init($0) } + }() + self.threeDS = { + guard let threeDS else { return [] } + return threeDS.map { .init($0) } + }() + self.wiiU = { + guard let wiiU else { return [] } + return wiiU.map { .init($0) } + }() + } + + } +} diff --git a/Sources/Public/Models/Amiibo/Amiibo+Release.swift b/Sources/Public/Models/Amiibo/Amiibo+Release.swift new file mode 100644 index 0000000..7bcbfff --- /dev/null +++ b/Sources/Public/Models/Amiibo/Amiibo+Release.swift @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +import Foundation + +extension Amiibo { + public struct Release: Sendable { + + // MARK: Properties + + public let america: Date? + public let australia: Date? + public let europe: Date? + public let japan: Date? + + // MARK: Initialisers + + init(_ payload: Components.Schemas.AmiiboRelease) { + self.america = payload.na + self.australia = payload.au + self.europe = payload.eu + self.japan = payload.jp + } + + } +} diff --git a/Sources/Public/Models/Amiibo/Amiibo+Usage.swift b/Sources/Public/Models/Amiibo/Amiibo+Usage.swift new file mode 100644 index 0000000..d2bda39 --- /dev/null +++ b/Sources/Public/Models/Amiibo/Amiibo+Usage.swift @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +extension Amiibo { + public struct Usage: Sendable { + + // MARK: Properties + + public let explanation: String + public let isWriteable: Bool + + // MARK: Initialisers + + init(_ payload: Components.Schemas.AmiiboUsage) { + self.explanation = payload.Usage + self.isWriteable = payload.write + } + + } +} diff --git a/Sources/Public/Models/AmiiboSeries.swift b/Sources/Public/Models/AmiiboSeries.swift new file mode 100644 index 0000000..68f00f0 --- /dev/null +++ b/Sources/Public/Models/AmiiboSeries.swift @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct AmiiboSeries: KeyNameModel { + + // MARK: Properties + + public let key: String + public let name: String + + // MARK: Initialisers + + init(_ payload: Components.Schemas.Tuple) { + self.key = payload.key + self.name = payload.name + } + +} diff --git a/Sources/Public/Models/AmiiboType.swift b/Sources/Public/Models/AmiiboType.swift new file mode 100644 index 0000000..0a75874 --- /dev/null +++ b/Sources/Public/Models/AmiiboType.swift @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct AmiiboType: KeyNameModel { + + // MARK: Properties + + public let key: String + public let name: String + + // MARK: Initialisers + + init(_ payload: Components.Schemas.Tuple) { + self.key = payload.key + self.name = payload.name + } + +} diff --git a/Sources/Public/Models/GameCharacter.swift b/Sources/Public/Models/GameCharacter.swift new file mode 100644 index 0000000..652ea4d --- /dev/null +++ b/Sources/Public/Models/GameCharacter.swift @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct GameCharacter: KeyNameModel { + + // MARK: Properties + + public let key: String + public let name: String + + // MARK: Initialisers + + init(_ payload: Components.Schemas.Tuple) { + self.key = payload.key + self.name = payload.name + } + +} diff --git a/Sources/Public/Models/GameSeries.swift b/Sources/Public/Models/GameSeries.swift new file mode 100644 index 0000000..a445472 --- /dev/null +++ b/Sources/Public/Models/GameSeries.swift @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +public struct GameSeries: KeyNameModel { + + // MARK: Properties + + public let key: String + public let name: String + + // MARK: Initialisers + + init(_ payload: Components.Schemas.Tuple) { + self.key = payload.key + self.name = payload.name + } + +} diff --git a/Sources/Public/Services/AmiiboService.swift b/Sources/Public/Services/AmiiboService.swift new file mode 100644 index 0000000..f0bdb2b --- /dev/null +++ b/Sources/Public/Services/AmiiboService.swift @@ -0,0 +1,231 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AmiiboAPI open source project +// +// Copyright (c) 2024 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------===// + +import Foundation +import OpenAPIRuntime + +public struct AmiiboService { + + // MARK: Properties + + private let client: Client + + // MARK: Initialisers + + public init() throws { + self.client = try .live + } + + // MARK: Functions + + public func getAmiibos( + by filter: AmiiboFilter = .init() + ) async throws -> [Amiibo] { + let response = try await client.getAmiibos( + .init(query: .init( + amiiboSeries: filter.series, + character: filter.gameCharacter, + gameseries: filter.gameSeries, + id: filter.identifier, + name: filter.name, + showgames: filter.showGames, + showusage: filter.showUsage, + _type: filter.type + )) + ) + + switch response { + case let .ok(okResponse): + switch okResponse.body { + case let .json(output): + switch output.amiibo { + case let .Amiibo(object): + return [.init(object)] + + case let .AmiiboList(list): + return list + .map { .init($0) } + .sorted { $0.identifier < $1.identifier } + } + } + + case .badRequest: + throw AmiiboServiceError.badRequest + + case let .undocumented(statusCode, _): + throw AmiiboServiceError.undocumented(statusCode) + } + } + + public func getAmiiboSeries( + by filter: AmiiboSeriesFilter = .init() + ) async throws -> [AmiiboSeries] { + let response = try await client.getAmiiboSeries( + .init(query: .init( + key: filter.key, + name: filter.name + )) + ) + + switch response { + case let .ok(okResponse): + switch okResponse.body { + case let .json(output): + return map(output, to: AmiiboSeries.self) + } + + case .badRequest: + throw AmiiboServiceError.badRequest + + case .internalServerError: + throw AmiiboServiceError.notAvailable + + case .notFound: + throw AmiiboServiceError.notFound + + case let .undocumented(statusCode, _): + throw AmiiboServiceError.undocumented(statusCode) + } + } + + public func getAmiiboTypes( + by filter: AmiiboTypeFilter = .init() + ) async throws -> [AmiiboType] { + let response = try await client.getAmiiboTypes( + .init(query: .init( + key: filter.key, + name: filter.name + )) + ) + + switch response { + case let .ok(okResponse): + switch okResponse.body { + case let .json(output): + return map(output, to: AmiiboType.self) + } + + case .badRequest: + throw AmiiboServiceError.badRequest + + case .internalServerError: + throw AmiiboServiceError.notAvailable + + case .notFound: + throw AmiiboServiceError.notFound + + case let .undocumented(statusCode, _): + throw AmiiboServiceError.undocumented(statusCode) + } + } + + public func getGameCharacters( + by filter: GameCharacterFilter = .init() + ) async throws -> [GameCharacter] { + let response = try await client.getGameCharacters( + .init(query: .init( + key: filter.key, + name: filter.name + )) + ) + + switch response { + case let .ok(okResponse): + switch okResponse.body { + case let .json(output): + return map(output, to: GameCharacter.self) + } + + case .badRequest: + throw AmiiboServiceError.badRequest + + case .internalServerError: + throw AmiiboServiceError.notAvailable + + case .notFound: + throw AmiiboServiceError.notFound + + case let .undocumented(statusCode, _): + throw AmiiboServiceError.undocumented(statusCode) + } + } + + public func getGameSeries( + by filter: GameSeriesFilter = .init() + ) async throws -> [GameSeries] { + let response = try await client.getGameSeries( + .init(query: .init( + key: filter.key, + name: filter.name + )) + ) + + switch response { + case let .ok(okResponse): + switch okResponse.body { + case let .json(output): + return map(output, to: GameSeries.self) + } + + case .badRequest: + throw AmiiboServiceError.badRequest + + case .internalServerError: + throw AmiiboServiceError.notAvailable + + case .notFound: + throw AmiiboServiceError.notFound + + case let .undocumented(statusCode, _): + throw AmiiboServiceError.undocumented(statusCode) + } + } + + public func getLastUpdated() async throws -> Date { + let response = try await client.getLastUpdated() + + switch response { + case let .ok(okResponse): + switch okResponse.body { + case let .json(output): + return output.lastUpdated + } + + case let .undocumented(statusCode, _): + throw AmiiboServiceError.undocumented(statusCode) + } + } + +} + +// MARK: - Helpers + +private extension AmiiboService { + + // MARK: Functions + + func map( + _ output: Components.Schemas.TupleWrapper, + to: Model.Type + ) -> [Model] { + switch output.amiibo { + case let .Tuple(payload): + return [.init(payload)] + + case let .TupleList(list): + return list + .map { .init($0) } + .sorted { $0.key < $1.key } + } + } + +} diff --git a/Sources/amiibo_api.swift b/Sources/amiibo_api.swift deleted file mode 100644 index 08b22b8..0000000 --- a/Sources/amiibo_api.swift +++ /dev/null @@ -1,2 +0,0 @@ -// The Swift Programming Language -// https://docs.swift.org/swift-book