DocC documentation support (#4)
This PR contains the work done to: * Documented all the `private`, `internal`, and `public` interfaces on the existing codebase; * Set the DocC documentation catalog in the project; * Written the main `Library` article for the DocC documentation catalog; * Added the documentation tasks in the `Makefile` file. Reviewed-on: #4 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #4.
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
# --- DOCUMENTATION ---
|
||||||
|
|
||||||
|
DOCC_CATALOG_PATH=./Catalogs/AmiiboService.docc
|
||||||
|
DOCC_GITHUB_OUTPUT=./docs
|
||||||
|
DOCC_GITHUB_BASE_PATH=amiibo-service
|
||||||
|
DOCC_PREVIEW_URL=http://localhost:8080/documentation/amiiboservice
|
||||||
|
DOCC_XCODE_OUTPUT=./${SPM_LIBRARY_TARGET}.doccarchive
|
||||||
|
|
||||||
|
# -- SWIFT PACKAGE MANAGER ---
|
||||||
|
|
||||||
|
SPM_LIBRARY_TARGET=AmiiboService
|
||||||
+4
-1
@@ -31,4 +31,7 @@ Packages/
|
|||||||
# hence it is not needed unless you have added a package configuration file to your project
|
# hence it is not needed unless you have added a package configuration file to your project
|
||||||
.swiftpm
|
.swiftpm
|
||||||
.swiftpm/configuration/registries.json
|
.swiftpm/configuration/registries.json
|
||||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
|
|
||||||
|
# DocC documentation
|
||||||
|
*.doccarchive
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# ``AmiiboService``
|
||||||
|
|
||||||
|
A library that provides everything the developer needs to interacts with the **Amiibo API** online service.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `AmiiboService` library is a Swift Package Manager package dependency aims at allowing the developer to interact with the [Amiibo API](https://www.amiiboapi.com) online service seamlessly, by not only providing the *service* tye but also any possible *clients*, *models*, *filters* and *errors* type that might be needed.
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
Although it could have been possible to generate a one-to-one RESTful client based on the Open API specification document that describe the available endpoints, it was decided to design a ``AmiiboService`` service that removes the complexities of the service's backend API, and provides the developer with a simple interface, and a seamless experience.
|
||||||
|
|
||||||
|
## Instalation
|
||||||
|
|
||||||
|
To use the `AmiiboService` library with your package, then add it as a dependency in the `Package.swift` file:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let package = Package(
|
||||||
|
// name, platforms, products, etc.
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/rock-n-code/amiibo-service", from: "1.0.0"),
|
||||||
|
// other dependencies
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "SomeTarget",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "AmiiboService", package: "amiibo-service"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
// other targets
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to use the `AmiiboService` library with your app in Xcode, then add it as a dependency in your Xcode project:
|
||||||
|
|
||||||
|
> important: Swift 5.9 or higher is required in order to compile this library.
|
||||||
|
|
||||||
|
## Topics
|
||||||
|
|
||||||
|
### Service
|
||||||
|
|
||||||
|
- ``AmiiboService``
|
||||||
|
|
||||||
|
### Clients
|
||||||
|
|
||||||
|
- ``AmiiboClient``
|
||||||
|
- ``AmiiboLiveClient``
|
||||||
|
- ``AmiiboMockClient``
|
||||||
|
|
||||||
|
### Models
|
||||||
|
|
||||||
|
- ``Amiibo``
|
||||||
|
- ``Amiibo/Game``
|
||||||
|
- ``Amiibo/Platform``
|
||||||
|
- ``Amiibo/Release``
|
||||||
|
- ``Amiibo/Usage``
|
||||||
|
- ``AmiiboSeries``
|
||||||
|
- ``AmiiboType``
|
||||||
|
- ``GameCharacter``
|
||||||
|
- ``GameSeries``
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
- ``AmiiboFilter``
|
||||||
|
- ``AmiiboSeriesFilter``
|
||||||
|
- ``AmiiboTypeFilter``
|
||||||
|
- ``GameCharacterFilter``
|
||||||
|
- ``GameSeriesFilter``
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
- ``AmiiboServiceError``
|
||||||
@@ -17,14 +17,6 @@ environment ?= .env
|
|||||||
include $(environment)
|
include $(environment)
|
||||||
export $(shell sed 's/=.*//' $(environment))
|
export $(shell sed 's/=.*//' $(environment))
|
||||||
|
|
||||||
# IDE
|
|
||||||
|
|
||||||
open-in-xcode: ## Opens this package with Xcode
|
|
||||||
@open -a Xcode Package.swift
|
|
||||||
|
|
||||||
open-in-vscode: ## Opens this package with Visual Studio Code
|
|
||||||
@code .
|
|
||||||
|
|
||||||
# SWIFT PACKAGE MANAGER
|
# SWIFT PACKAGE MANAGER
|
||||||
|
|
||||||
package-build: ## Builds the project locally
|
package-build: ## Builds the project locally
|
||||||
@@ -41,6 +33,45 @@ package-reset: ## Resets the complete SPM cache/build folder from the package
|
|||||||
|
|
||||||
package-update: ## Updates the SPM package dependencies
|
package-update: ## Updates the SPM package dependencies
|
||||||
@swift package update
|
@swift package update
|
||||||
|
|
||||||
|
# DOCUMENTATION
|
||||||
|
|
||||||
|
doc-generate: doc-generate-xcode doc-generate-github ## Generates the library documentation for both Github and Xcode
|
||||||
|
|
||||||
|
doc-generate-github: ## Generates the library documentation for Github
|
||||||
|
@swift package \
|
||||||
|
--allow-writing-to-directory $(DOCC_GITHUB_OUTPUT) \
|
||||||
|
generate-documentation \
|
||||||
|
$(DOCC_CATALOG_PATH) \
|
||||||
|
--target $(SPM_LIBRARY_TARGET) \
|
||||||
|
--disable-indexing \
|
||||||
|
--transform-for-static-hosting \
|
||||||
|
--hosting-base-path $(DOCC_GITHUB_BASE_PATH) \
|
||||||
|
--output-path $(DOCC_GITHUB_OUTPUT)
|
||||||
|
|
||||||
|
doc-generate-xcode: ## Generates the library documentation for Xcode
|
||||||
|
@swift package \
|
||||||
|
--allow-writing-to-directory $(DOCC_XCODE_OUTPUT) \
|
||||||
|
generate-documentation \
|
||||||
|
$(DOCC_CATALOG_PATH) \
|
||||||
|
--target $(SPM_LIBRARY_TARGET) \
|
||||||
|
--output-path $(DOCC_XCODE_OUTPUT)
|
||||||
|
|
||||||
|
doc-preview: ## Previews the library documentation in Safari
|
||||||
|
@open -a safari $(DOCC_PREVIEW_URL)
|
||||||
|
@swift package \
|
||||||
|
--disable-sandbox \
|
||||||
|
preview-documentation \
|
||||||
|
$(DOCC_CATALOG_PATH) \
|
||||||
|
--target $(SPM_LIBRARY_TARGET)
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
|
||||||
|
open-in-xcode: ## Opens this package with Xcode
|
||||||
|
@open -a Xcode Package.swift
|
||||||
|
|
||||||
|
open-in-vscode: ## Opens this package with Visual Studio Code
|
||||||
|
@code .
|
||||||
|
|
||||||
# HELP
|
# HELP
|
||||||
|
|
||||||
|
|||||||
+8
-27
@@ -26,44 +26,25 @@ let package = Package(
|
|||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: AmiiboService.package,
|
name: AmiiboService.package,
|
||||||
targets: [
|
targets: [AmiiboService.target]
|
||||||
AmiiboService.target
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(
|
.package(url: "https://github.com/apple/swift-openapi-generator.git", from: "1.3.0"),
|
||||||
url: "https://github.com/apple/swift-openapi-generator.git",
|
.package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.5.0"),
|
||||||
from: "1.3.0"
|
.package(url: "https://github.com/apple/swift-openapi-urlsession", from: "1.0.2"),
|
||||||
),
|
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"),
|
||||||
.package(
|
|
||||||
url: "https://github.com/apple/swift-openapi-runtime",
|
|
||||||
from: "1.5.0"
|
|
||||||
),
|
|
||||||
.package(
|
|
||||||
url: "https://github.com/apple/swift-openapi-urlsession",
|
|
||||||
from: "1.0.2"
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
name: AmiiboService.target,
|
name: AmiiboService.target,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(
|
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
||||||
name: "OpenAPIRuntime",
|
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession")
|
||||||
package: "swift-openapi-runtime"
|
|
||||||
),
|
|
||||||
.product(
|
|
||||||
name: "OpenAPIURLSession",
|
|
||||||
package: "swift-openapi-urlsession"
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
path: "Sources",
|
path: "Sources",
|
||||||
plugins: [
|
plugins: [
|
||||||
.plugin(
|
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
|
||||||
name: "OpenAPIGenerator",
|
|
||||||
package: "swift-openapi-generator"
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ import Foundation
|
|||||||
|
|
||||||
extension DateFormatter {
|
extension DateFormatter {
|
||||||
|
|
||||||
static var isoDateTime: DateFormatter {
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// An ISO timestamp formatter.
|
||||||
|
///
|
||||||
|
/// This formatter implements the `yyyy-MM-dd'T'HH:mm:ss.SSSSSS` custom date format.
|
||||||
|
/// Within the context of this library, this formatter is solely used to decode a date formatted as a timestamp that is returned by the ``AmiiboService/getLastUpdated()`` function.
|
||||||
|
static var isoTimestamp: DateFormatter {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
|
|
||||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"
|
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"
|
||||||
|
|||||||
@@ -12,15 +12,44 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public protocol APIClient {
|
/// A protocol that defines API clients containing all available endpoints to interact with.
|
||||||
|
protocol APIClient {
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
func getAmiibos(by filter: AmiiboFilter) async throws -> [Amiibo]
|
/// Gets a list of amiibo items based on a given filter.
|
||||||
func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws -> [AmiiboSeries]
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws -> [AmiiboType]
|
/// - Returns: A list of filtered amiibo items.
|
||||||
func getGameCharacters(by filter: GameCharacterFilter) async throws -> [GameCharacter]
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
func getGameSeries(by filter: GameSeriesFilter) async throws -> [GameSeries]
|
func getAmiibos(by filter: AmiiboFilter) async throws(AmiiboServiceError) -> [Amiibo]
|
||||||
func getLastUpdated() async throws -> Date
|
|
||||||
|
/// Gets a list of amiibo series based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered amiibo series.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
|
func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws(AmiiboServiceError) -> [AmiiboSeries]
|
||||||
|
|
||||||
|
/// Gets a list of amiibo types based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered amiibo types.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
|
func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws(AmiiboServiceError) -> [AmiiboType]
|
||||||
|
|
||||||
|
/// Gets a list of game characters based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered game characters.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
|
func getGameCharacters(by filter: GameCharacterFilter) async throws(AmiiboServiceError) -> [GameCharacter]
|
||||||
|
|
||||||
|
/// Gets a list of game series based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered game series.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
|
func getGameSeries(by filter: GameSeriesFilter) async throws(AmiiboServiceError) -> [GameSeries]
|
||||||
|
|
||||||
|
/// Gets the date when the data was last updated.
|
||||||
|
/// - Returns: A last updated date.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
|
func getLastUpdated() async throws(AmiiboServiceError) -> Date
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,28 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A protocol that defines filters that might contain `key` and/or `name` values.
|
||||||
protocol KeyNameFilter {
|
protocol KeyNameFilter {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A key to use for filtering, if any.
|
||||||
var key: String? { get }
|
var key: String? { get }
|
||||||
|
|
||||||
|
/// A name to use for filtering, if any.
|
||||||
var name: String? { get }
|
var name: String? { get }
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this filter without key or name values.
|
||||||
init()
|
init()
|
||||||
|
|
||||||
|
/// Initializes this filter with a key value.
|
||||||
|
/// - Parameter key: A key to use for filtering.
|
||||||
init(key: String)
|
init(key: String)
|
||||||
|
|
||||||
|
/// Initializes this filter with a name value.
|
||||||
|
/// - Parameter name: A name to use for filtering.
|
||||||
init(name: String)
|
init(name: String)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,21 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A protocol that defines decodable models containing the `key` and `name` properties.
|
||||||
protocol KeyNameModel: Sendable {
|
protocol KeyNameModel: Sendable {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A key.
|
||||||
var key: String { get }
|
var key: String { get }
|
||||||
|
|
||||||
|
/// A name.
|
||||||
var name: String { get }
|
var name: String { get }
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this model from a given payload.
|
||||||
|
/// - Parameter payload: A payload that contains the values for the model.
|
||||||
init(_ payload: Components.Schemas.Tuple)
|
init(_ payload: Components.Schemas.Tuple)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -13,10 +13,19 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import OpenAPIRuntime
|
import OpenAPIRuntime
|
||||||
|
|
||||||
struct ISODateTranscoder: DateTranscoder {
|
/// A type that allows the decoding and encoding of ISO timestamp dates, defined by the `yyyy-MM-dd'T'HH:mm:ss.SSSSSS` custom date format.
|
||||||
|
struct ISOTimestampTranscoder {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
private let dateFormatter: DateFormatter = .isoDateTime
|
|
||||||
|
/// A formatter to use to decode and encode ISO timestamps dates.
|
||||||
|
private let dateFormatter: DateFormatter = .isoTimestamp
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - DateTranscoder
|
||||||
|
|
||||||
|
extension ISOTimestampTranscoder: DateTranscoder {
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
@@ -14,55 +14,61 @@ import Foundation
|
|||||||
import OpenAPIRuntime
|
import OpenAPIRuntime
|
||||||
import OpenAPIURLSession
|
import OpenAPIURLSession
|
||||||
|
|
||||||
|
/// A type that implements a live client to the online service.
|
||||||
public struct AmiiboLiveClient {
|
public struct AmiiboLiveClient {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A client generated by the `OpenAPIRuntime` library.
|
||||||
private let client: Client
|
private let client: Client
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
public init() throws {
|
/// Initializes this client.
|
||||||
|
public init() {
|
||||||
self.client = .init(
|
self.client = .init(
|
||||||
serverURL: try Servers.Server1.url(),
|
// The force unwrapping implemented below assumes that the server definition from the OpenAPI specification is correct.
|
||||||
configuration: .init(dateTranscoder: ISODateTranscoder()),
|
serverURL: try! Servers.Server1.url(),
|
||||||
|
configuration: .init(dateTranscoder: ISOTimestampTranscoder()),
|
||||||
transport: URLSessionTransport()
|
transport: URLSessionTransport()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - APIProtocol
|
// MARK: - APIClient
|
||||||
|
|
||||||
extension AmiiboLiveClient: APIClient {
|
extension AmiiboLiveClient: APIClient {
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
public func getAmiibos(by filter: AmiiboFilter) async throws -> [Amiibo] {
|
public func getAmiibos(
|
||||||
let response = try await {
|
by filter: AmiiboFilter
|
||||||
do {
|
) async throws(AmiiboServiceError) -> [Amiibo] {
|
||||||
return try await client.getAmiibos(
|
let response: Operations.getAmiibos.Output
|
||||||
.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
|
|
||||||
))
|
|
||||||
)
|
|
||||||
} catch let error as ClientError {
|
|
||||||
guard let _ = error.underlyingError as? DecodingError else {
|
|
||||||
throw AmiiboServiceError.unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
|
do {
|
||||||
|
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
|
||||||
|
))
|
||||||
|
)
|
||||||
|
} catch let error as ClientError {
|
||||||
|
if error.underlyingError is DecodingError {
|
||||||
throw AmiiboServiceError.decoding
|
throw AmiiboServiceError.decoding
|
||||||
} catch {
|
} else {
|
||||||
throw AmiiboServiceError.unknown
|
throw AmiiboServiceError.unknown
|
||||||
}
|
}
|
||||||
}()
|
} catch {
|
||||||
|
throw AmiiboServiceError.unknown
|
||||||
|
}
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case let .ok(ok):
|
case let .ok(ok):
|
||||||
@@ -79,13 +85,21 @@ extension AmiiboLiveClient: APIClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws -> [AmiiboSeries] {
|
public func getAmiiboSeries(
|
||||||
let response = try await client.getAmiiboSeries(
|
by filter: AmiiboSeriesFilter
|
||||||
.init(query: .init(
|
) async throws(AmiiboServiceError) -> [AmiiboSeries] {
|
||||||
key: filter.key,
|
let response: Operations.getAmiiboSeries.Output
|
||||||
name: filter.name
|
|
||||||
))
|
do {
|
||||||
)
|
response = try await client.getAmiiboSeries(
|
||||||
|
.init(query: .init(
|
||||||
|
key: filter.key,
|
||||||
|
name: filter.name
|
||||||
|
))
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AmiiboServiceError.unknown
|
||||||
|
}
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case let .ok(ok):
|
case let .ok(ok):
|
||||||
@@ -108,13 +122,21 @@ extension AmiiboLiveClient: APIClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws -> [AmiiboType] {
|
public func getAmiiboTypes(
|
||||||
let response = try await client.getAmiiboTypes(
|
by filter: AmiiboTypeFilter
|
||||||
.init(query: .init(
|
) async throws(AmiiboServiceError) -> [AmiiboType] {
|
||||||
key: filter.key,
|
let response: Operations.getAmiiboTypes.Output
|
||||||
name: filter.name
|
|
||||||
))
|
do {
|
||||||
)
|
response = try await client.getAmiiboTypes(
|
||||||
|
.init(query: .init(
|
||||||
|
key: filter.key,
|
||||||
|
name: filter.name
|
||||||
|
))
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AmiiboServiceError.unknown
|
||||||
|
}
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case let .ok(ok):
|
case let .ok(ok):
|
||||||
@@ -137,13 +159,21 @@ extension AmiiboLiveClient: APIClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getGameCharacters(by filter: GameCharacterFilter) async throws -> [GameCharacter] {
|
public func getGameCharacters(
|
||||||
let response = try await client.getGameCharacters(
|
by filter: GameCharacterFilter
|
||||||
.init(query: .init(
|
) async throws(AmiiboServiceError) -> [GameCharacter] {
|
||||||
key: filter.key,
|
let response: Operations.getGameCharacters.Output
|
||||||
name: filter.name
|
|
||||||
))
|
do {
|
||||||
)
|
response = try await client.getGameCharacters(
|
||||||
|
.init(query: .init(
|
||||||
|
key: filter.key,
|
||||||
|
name: filter.name
|
||||||
|
))
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AmiiboServiceError.unknown
|
||||||
|
}
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case let .ok(ok):
|
case let .ok(ok):
|
||||||
@@ -166,13 +196,21 @@ extension AmiiboLiveClient: APIClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getGameSeries(by filter: GameSeriesFilter) async throws -> [GameSeries] {
|
public func getGameSeries(
|
||||||
let response = try await client.getGameSeries(
|
by filter: GameSeriesFilter
|
||||||
.init(query: .init(
|
) async throws(AmiiboServiceError) -> [GameSeries] {
|
||||||
key: filter.key,
|
let response: Operations.getGameSeries.Output
|
||||||
name: filter.name
|
|
||||||
))
|
do {
|
||||||
)
|
response = try await client.getGameSeries(
|
||||||
|
.init(query: .init(
|
||||||
|
key: filter.key,
|
||||||
|
name: filter.name
|
||||||
|
))
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AmiiboServiceError.unknown
|
||||||
|
}
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case let .ok(ok):
|
case let .ok(ok):
|
||||||
@@ -195,8 +233,14 @@ extension AmiiboLiveClient: APIClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getLastUpdated() async throws -> Date {
|
public func getLastUpdated() async throws(AmiiboServiceError) -> Date {
|
||||||
let response = try await client.getLastUpdated()
|
let response: Operations.getLastUpdated.Output
|
||||||
|
|
||||||
|
do {
|
||||||
|
response = try await client.getLastUpdated()
|
||||||
|
} catch {
|
||||||
|
throw AmiiboServiceError.unknown
|
||||||
|
}
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case let .ok(ok):
|
case let .ok(ok):
|
||||||
@@ -218,7 +262,12 @@ private extension AmiiboLiveClient {
|
|||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
func map(_ wrapper: Components.Schemas.AmiiboWrapper) -> [Amiibo] {
|
/// Retrieves a list of amiibo items from a wrapper container.
|
||||||
|
/// - Parameter wrapper: A wrapper container that either has an object or a list of items.
|
||||||
|
/// - Returns: A list of amiibo items, sorted by identifiers.
|
||||||
|
func map(
|
||||||
|
_ wrapper: Components.Schemas.AmiiboWrapper
|
||||||
|
) -> [Amiibo] {
|
||||||
switch wrapper.amiibo {
|
switch wrapper.amiibo {
|
||||||
case let .Amiibo(object):
|
case let .Amiibo(object):
|
||||||
return [.init(object)]
|
return [.init(object)]
|
||||||
@@ -230,6 +279,11 @@ private extension AmiiboLiveClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves a list of items that conforms to the `KeyNameModel` protocol from a wrapper container.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - wrapper: A wrapper container that either has an object or a list of items.
|
||||||
|
/// - as: a model type that conforms to the `KeyNameModel` protocol.
|
||||||
|
/// - Returns: A list of items that conforms to the `KeyNameModel` protocol, sorted by keys.
|
||||||
func map<Model: KeyNameModel>(
|
func map<Model: KeyNameModel>(
|
||||||
_ wrapper: Components.Schemas.TupleWrapper,
|
_ wrapper: Components.Schemas.TupleWrapper,
|
||||||
as: Model.Type
|
as: Model.Type
|
||||||
|
|||||||
@@ -12,20 +12,43 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// A type that implements a mock client, for testing purposes.
|
||||||
public struct AmiiboMockClient {
|
public struct AmiiboMockClient {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A list of amiibo items to return, if any.
|
||||||
private let amiibos: [Amiibo]?
|
private let amiibos: [Amiibo]?
|
||||||
|
|
||||||
|
/// A list of amiibo series to return, if any.
|
||||||
private let amiiboSeries: [AmiiboSeries]?
|
private let amiiboSeries: [AmiiboSeries]?
|
||||||
|
|
||||||
|
/// A list of amiibo types to return, if any.
|
||||||
private let amiiboTypes: [AmiiboType]?
|
private let amiiboTypes: [AmiiboType]?
|
||||||
|
|
||||||
|
/// An error to throw, if any.
|
||||||
private let error: AmiiboServiceError?
|
private let error: AmiiboServiceError?
|
||||||
|
|
||||||
|
/// A list of game characters to return, if any.
|
||||||
private let gameCharacters: [GameCharacter]?
|
private let gameCharacters: [GameCharacter]?
|
||||||
|
|
||||||
|
/// A list of game series to return, if any.
|
||||||
private let gameSeries: [GameSeries]?
|
private let gameSeries: [GameSeries]?
|
||||||
|
|
||||||
|
/// A last updated date to return, if any.
|
||||||
private let lastUpdated: Date?
|
private let lastUpdated: Date?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this client.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - amiibos: A list of amiibo items to return, if any.
|
||||||
|
/// - amiiboSeries: A list of amiibo series to return, if any.
|
||||||
|
/// - amiiboTypes: A list of amiibo types to return, if any.
|
||||||
|
/// - gameCharacters: A list of game characters to return, if any.
|
||||||
|
/// - gameSeries: A list of game series to return, if any.
|
||||||
|
/// - lastUpdated: A last updated date to return, if any.
|
||||||
|
/// - error: An error to throw, if any.
|
||||||
public init(
|
public init(
|
||||||
amiibos: [Amiibo]? = nil,
|
amiibos: [Amiibo]? = nil,
|
||||||
amiiboSeries: [AmiiboSeries]? = nil,
|
amiiboSeries: [AmiiboSeries]? = nil,
|
||||||
@@ -52,7 +75,7 @@ extension AmiiboMockClient: APIClient {
|
|||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
public func getAmiibos(by filter: AmiiboFilter) async throws -> [Amiibo] {
|
public func getAmiibos(by filter: AmiiboFilter) async throws(AmiiboServiceError) -> [Amiibo] {
|
||||||
try throwErrorIfExists()
|
try throwErrorIfExists()
|
||||||
|
|
||||||
guard let amiibos else {
|
guard let amiibos else {
|
||||||
@@ -62,7 +85,7 @@ extension AmiiboMockClient: APIClient {
|
|||||||
return amiibos
|
return amiibos
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws -> [AmiiboSeries] {
|
public func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws(AmiiboServiceError) -> [AmiiboSeries] {
|
||||||
try throwErrorIfExists()
|
try throwErrorIfExists()
|
||||||
|
|
||||||
guard let amiiboSeries else {
|
guard let amiiboSeries else {
|
||||||
@@ -72,7 +95,7 @@ extension AmiiboMockClient: APIClient {
|
|||||||
return amiiboSeries
|
return amiiboSeries
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws -> [AmiiboType] {
|
public func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws(AmiiboServiceError) -> [AmiiboType] {
|
||||||
try throwErrorIfExists()
|
try throwErrorIfExists()
|
||||||
|
|
||||||
guard let amiiboTypes else {
|
guard let amiiboTypes else {
|
||||||
@@ -82,7 +105,7 @@ extension AmiiboMockClient: APIClient {
|
|||||||
return amiiboTypes
|
return amiiboTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getGameCharacters(by filter: GameCharacterFilter) async throws -> [GameCharacter] {
|
public func getGameCharacters(by filter: GameCharacterFilter) async throws(AmiiboServiceError) -> [GameCharacter] {
|
||||||
try throwErrorIfExists()
|
try throwErrorIfExists()
|
||||||
|
|
||||||
guard let gameCharacters else {
|
guard let gameCharacters else {
|
||||||
@@ -92,7 +115,7 @@ extension AmiiboMockClient: APIClient {
|
|||||||
return gameCharacters
|
return gameCharacters
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getGameSeries(by filter: GameSeriesFilter) async throws -> [GameSeries] {
|
public func getGameSeries(by filter: GameSeriesFilter) async throws(AmiiboServiceError) -> [GameSeries] {
|
||||||
try throwErrorIfExists()
|
try throwErrorIfExists()
|
||||||
|
|
||||||
guard let gameSeries else {
|
guard let gameSeries else {
|
||||||
@@ -102,7 +125,7 @@ extension AmiiboMockClient: APIClient {
|
|||||||
return gameSeries
|
return gameSeries
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getLastUpdated() async throws -> Date {
|
public func getLastUpdated() async throws(AmiiboServiceError) -> Date {
|
||||||
try throwErrorIfExists()
|
try throwErrorIfExists()
|
||||||
|
|
||||||
guard let lastUpdated else {
|
guard let lastUpdated else {
|
||||||
@@ -121,7 +144,9 @@ private extension AmiiboMockClient {
|
|||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
func throwErrorIfExists() throws {
|
/// Throws an error if it has been provided,
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case an error has been provided.
|
||||||
|
func throwErrorIfExists() throws(AmiiboServiceError) {
|
||||||
if let error {
|
if let error {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//===----------------------------------------------------------------------===
|
||||||
|
//
|
||||||
|
// This source file is part of the AmiiboService open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2024-2025 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A concrete representation of the types of client that a ``AmiiboService`` service can utilize.
|
||||||
|
///
|
||||||
|
/// > important: This enumeration has been defined as a way to avoid exposing the `APIClient` protocol outside the boundaries of this library.
|
||||||
|
public enum AmiiboClient {
|
||||||
|
/// A live Amiibo client to interact with the online service.
|
||||||
|
case live(AmiiboLiveClient = .init())
|
||||||
|
///A mock Amiibo client, for testing purposes.
|
||||||
|
case mock(AmiiboMockClient)
|
||||||
|
}
|
||||||
@@ -10,12 +10,19 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A representation of all the possible errors that the ``AmiiboService`` service could throw.
|
||||||
public enum AmiiboServiceError: Error {
|
public enum AmiiboServiceError: Error {
|
||||||
|
/// A bad request has been given to the client.
|
||||||
case badRequest
|
case badRequest
|
||||||
|
/// A response cannot be decoded.
|
||||||
case decoding
|
case decoding
|
||||||
|
/// An online service is not currently available.
|
||||||
case notAvailable
|
case notAvailable
|
||||||
|
/// A response cannot be found.
|
||||||
case notFound
|
case notFound
|
||||||
|
/// An undocumented/unsupported status code error.
|
||||||
case undocumented(_ statusCode: Int)
|
case undocumented(_ statusCode: Int)
|
||||||
|
/// An unknown error.
|
||||||
case unknown
|
case unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,21 +10,47 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A type that contains values to fine-tune a response when requesting amiibo items.
|
||||||
public struct AmiiboFilter {
|
public struct AmiiboFilter {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A game character to return, if any.
|
||||||
public let gameCharacter: String?
|
public let gameCharacter: String?
|
||||||
|
|
||||||
|
/// A game series to return, if any.
|
||||||
public let gameSeries: String?
|
public let gameSeries: String?
|
||||||
|
|
||||||
|
/// An amiibo identifier to return, if any.
|
||||||
public let identifier: String?
|
public let identifier: String?
|
||||||
|
|
||||||
|
/// An amiibo name to return, if any.
|
||||||
public let name: String?
|
public let name: String?
|
||||||
|
|
||||||
|
/// An amiibo series to return, if any.
|
||||||
public let series: String?
|
public let series: String?
|
||||||
|
|
||||||
|
/// A flag indicating whether to include games in the response, if any.
|
||||||
public let showGames: Bool?
|
public let showGames: Bool?
|
||||||
|
|
||||||
|
/// A flag indicating whether to include amiibo usages in games in the response, if any.
|
||||||
public let showUsage: Bool?
|
public let showUsage: Bool?
|
||||||
|
|
||||||
|
/// An amiibo type to return, if any.
|
||||||
public let type: String?
|
public let type: String?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this filter.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - identifier: An amiibo identifier to return, if any.
|
||||||
|
/// - name: An amiibo name to return, if any.
|
||||||
|
/// - type: An amiibo type to return, if any.
|
||||||
|
/// - series: An amiibo series to return, if any.
|
||||||
|
/// - gameCharacter: A game character to return, if any.
|
||||||
|
/// - gameSeries: A game series to return, if any.
|
||||||
|
/// - showGames: A flag indicating whether to include games in the response, if any.
|
||||||
|
/// - showUsage: A flag indicating whether to include amiibo usages in games in the response, if any.
|
||||||
public init(
|
public init(
|
||||||
identifier: String? = nil,
|
identifier: String? = nil,
|
||||||
name: String? = nil,
|
name: String? = nil,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A type that contains values to fine-tune a response when requesting amiibo series.
|
||||||
public struct AmiiboSeriesFilter: KeyNameFilter {
|
public struct AmiiboSeriesFilter: KeyNameFilter {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct AmiiboSeriesFilter: KeyNameFilter {
|
|||||||
public let key: String?
|
public let key: String?
|
||||||
public let name: String?
|
public let name: String?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
self.key = nil
|
self.key = nil
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A type that contains values to fine-tune a response when requesting amiibo types.
|
||||||
public struct AmiiboTypeFilter: KeyNameFilter {
|
public struct AmiiboTypeFilter: KeyNameFilter {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct AmiiboTypeFilter: KeyNameFilter {
|
|||||||
public let key: String?
|
public let key: String?
|
||||||
public let name: String?
|
public let name: String?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
self.key = nil
|
self.key = nil
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A type that contains values to fine-tune a response when requesting game characters.
|
||||||
public struct GameCharacterFilter: KeyNameFilter {
|
public struct GameCharacterFilter: KeyNameFilter {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct GameCharacterFilter: KeyNameFilter {
|
|||||||
public let key: String?
|
public let key: String?
|
||||||
public let name: String?
|
public let name: String?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
self.key = nil
|
self.key = nil
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A type that contains values to fine-tune a response when requesting game series.
|
||||||
public struct GameSeriesFilter: KeyNameFilter {
|
public struct GameSeriesFilter: KeyNameFilter {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct GameSeriesFilter: KeyNameFilter {
|
|||||||
public let key: String?
|
public let key: String?
|
||||||
public let name: String?
|
public let name: String?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
self.key = nil
|
self.key = nil
|
||||||
|
|||||||
@@ -12,23 +12,45 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// A model that represents an amiibo item.
|
||||||
public struct Amiibo: Sendable {
|
public struct Amiibo: Sendable {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A game character.
|
||||||
public let gameCharacter: String
|
public let gameCharacter: String
|
||||||
|
|
||||||
|
/// A game series.
|
||||||
public let gameSeries: String
|
public let gameSeries: String
|
||||||
|
|
||||||
|
/// The first 8 hexadecimal characters of an identifier.
|
||||||
public let head: String
|
public let head: String
|
||||||
|
|
||||||
|
/// An image link.
|
||||||
public let image: String
|
public let image: String
|
||||||
|
|
||||||
|
/// An amiibo name.
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
|
/// A game platform type, if any.
|
||||||
public let platform: Platform?
|
public let platform: Platform?
|
||||||
|
|
||||||
|
/// A release date.
|
||||||
public let release: Release
|
public let release: Release
|
||||||
|
|
||||||
|
/// An amiibo series.
|
||||||
public let series: String
|
public let series: String
|
||||||
|
|
||||||
|
/// The last 8 hexadecimal characters of an identifier.
|
||||||
public let tail: String
|
public let tail: String
|
||||||
|
|
||||||
|
/// An amiibo type.
|
||||||
public let type: String
|
public let type: String
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this model from a given payload.
|
||||||
|
/// - Parameter payload: A payload that contains the values for the model.
|
||||||
init(_ payload: Components.Schemas.Amiibo) {
|
init(_ payload: Components.Schemas.Amiibo) {
|
||||||
self.gameCharacter = payload.character
|
self.gameCharacter = payload.character
|
||||||
self.gameSeries = payload.gameSeries
|
self.gameSeries = payload.gameSeries
|
||||||
@@ -48,10 +70,12 @@ public struct Amiibo: Sendable {
|
|||||||
|
|
||||||
// MARK: Computed
|
// MARK: Computed
|
||||||
|
|
||||||
|
/// An identifier.
|
||||||
public var identifier: String {
|
public var identifier: String {
|
||||||
head + tail
|
head + tail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A URL related to an image link, if any.
|
||||||
public var imageURL: URL? {
|
public var imageURL: URL? {
|
||||||
.init(string: image)
|
.init(string: image)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,16 +11,24 @@
|
|||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
extension Amiibo {
|
extension Amiibo {
|
||||||
|
/// A model that represents a game related to an amiibo item.
|
||||||
public struct Game: Sendable {
|
public struct Game: Sendable {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A list of identifiers.
|
||||||
public let identifiers: [String]
|
public let identifiers: [String]
|
||||||
|
|
||||||
|
/// A name.
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
|
/// A list of amiibo usages, if any.
|
||||||
public let usages: [Usage]?
|
public let usages: [Usage]?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this model from a given payload.
|
||||||
|
/// - Parameter payload: A payload that contains the values for the model.
|
||||||
init(_ payload: Components.Schemas.AmiiboGame) {
|
init(_ payload: Components.Schemas.AmiiboGame) {
|
||||||
self.identifiers = payload.gameID
|
self.identifiers = payload.gameID
|
||||||
self.name = payload.gameName
|
self.name = payload.gameName
|
||||||
|
|||||||
@@ -11,16 +11,30 @@
|
|||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
extension Amiibo {
|
extension Amiibo {
|
||||||
|
/// A model that represents a collection of `WiiU`, `3DS`, and `Switch` games related to an amiibo item.
|
||||||
public struct Platform: Sendable {
|
public struct Platform: Sendable {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A list of `Switch` games related to an amiibo item.
|
||||||
public let `switch`: [Game]
|
public let `switch`: [Game]
|
||||||
|
|
||||||
|
/// A list of `3DS` games related to an amiibo item.
|
||||||
public let threeDS: [Game]
|
public let threeDS: [Game]
|
||||||
|
|
||||||
|
/// A list of `WiiU` games related to an amiibo item.
|
||||||
public let wiiU: [Game]
|
public let wiiU: [Game]
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
|
|
||||||
|
/// Initializes this model.
|
||||||
|
///
|
||||||
|
/// > important: In case no data is provided, then an instance of this model is not created.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - `switch`: A list of `Switch` games related to an amiibo item, if any.
|
||||||
|
/// - threeDS: A list of `3DS` games related to an amiibo item, if any.
|
||||||
|
/// - wiiU: A list of `WiiU` games related to an amiibo item, if any.
|
||||||
init?(
|
init?(
|
||||||
_ `switch`: [Components.Schemas.AmiiboGame]?,
|
_ `switch`: [Components.Schemas.AmiiboGame]?,
|
||||||
_ threeDS: [Components.Schemas.AmiiboGame]?,
|
_ threeDS: [Components.Schemas.AmiiboGame]?,
|
||||||
|
|||||||
@@ -13,17 +13,27 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension Amiibo {
|
extension Amiibo {
|
||||||
|
/// A model that represents a collection of release dates related to an amiibo item.
|
||||||
public struct Release: Sendable {
|
public struct Release: Sendable {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A release date for North America, if any.
|
||||||
public let america: Date?
|
public let america: Date?
|
||||||
|
|
||||||
|
/// A release date for Australia, if any.
|
||||||
public let australia: Date?
|
public let australia: Date?
|
||||||
|
|
||||||
|
/// A release date for Europe, if any.
|
||||||
public let europe: Date?
|
public let europe: Date?
|
||||||
|
|
||||||
|
/// A release date for Japan, if any.
|
||||||
public let japan: Date?
|
public let japan: Date?
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this model from a given payload.
|
||||||
|
/// - Parameter payload: A payload that contains the values for the model.
|
||||||
init(_ payload: Components.Schemas.AmiiboRelease) {
|
init(_ payload: Components.Schemas.AmiiboRelease) {
|
||||||
self.america = payload.na
|
self.america = payload.na
|
||||||
self.australia = payload.au
|
self.australia = payload.au
|
||||||
|
|||||||
@@ -11,15 +11,21 @@
|
|||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
extension Amiibo {
|
extension Amiibo {
|
||||||
|
/// A model that represents the usage of an amiibo item within a certain game.
|
||||||
public struct Usage: Sendable {
|
public struct Usage: Sendable {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// An explanation of how to use an amiibo item.
|
||||||
public let explanation: String
|
public let explanation: String
|
||||||
|
|
||||||
|
/// A flag that indicates whether an amiibo item can save game data in it.
|
||||||
public let isWriteable: Bool
|
public let isWriteable: Bool
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
|
/// Initializes this model from a given payload.
|
||||||
|
/// - Parameter payload: A payload that contains the values for the model.
|
||||||
init(_ payload: Components.Schemas.AmiiboUsage) {
|
init(_ payload: Components.Schemas.AmiiboUsage) {
|
||||||
self.explanation = payload.Usage
|
self.explanation = payload.Usage
|
||||||
self.isWriteable = payload.write
|
self.isWriteable = payload.write
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A model that represents an amiibo series.
|
||||||
public struct AmiiboSeries: KeyNameModel {
|
public struct AmiiboSeries: KeyNameModel {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct AmiiboSeries: KeyNameModel {
|
|||||||
public let key: String
|
public let key: String
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
init(_ payload: Components.Schemas.Tuple) {
|
init(_ payload: Components.Schemas.Tuple) {
|
||||||
self.key = payload.key
|
self.key = payload.key
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A model that represents an amiibo type.
|
||||||
public struct AmiiboType: KeyNameModel {
|
public struct AmiiboType: KeyNameModel {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct AmiiboType: KeyNameModel {
|
|||||||
public let key: String
|
public let key: String
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
init(_ payload: Components.Schemas.Tuple) {
|
init(_ payload: Components.Schemas.Tuple) {
|
||||||
self.key = payload.key
|
self.key = payload.key
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A model that represents a game character.
|
||||||
public struct GameCharacter: KeyNameModel {
|
public struct GameCharacter: KeyNameModel {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct GameCharacter: KeyNameModel {
|
|||||||
public let key: String
|
public let key: String
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
init(_ payload: Components.Schemas.Tuple) {
|
init(_ payload: Components.Schemas.Tuple) {
|
||||||
self.key = payload.key
|
self.key = payload.key
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
/// A model that represents a game series.
|
||||||
public struct GameSeries: KeyNameModel {
|
public struct GameSeries: KeyNameModel {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@@ -17,7 +18,7 @@ public struct GameSeries: KeyNameModel {
|
|||||||
public let key: String
|
public let key: String
|
||||||
public let name: String
|
public let name: String
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
init(_ payload: Components.Schemas.Tuple) {
|
init(_ payload: Components.Schemas.Tuple) {
|
||||||
self.key = payload.key
|
self.key = payload.key
|
||||||
|
|||||||
@@ -12,51 +12,81 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// A type that implements the service that uses a client to make calls.
|
||||||
public struct AmiiboService {
|
public struct AmiiboService {
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// A client to interact with the endpoints.
|
||||||
private let client: any APIClient
|
private let client: any APIClient
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initializers
|
||||||
|
|
||||||
public init(_ client: any APIClient) {
|
/// Initializes this service with a specific client type.
|
||||||
self.client = client
|
/// - Parameter client: A representation of a client to use to interact with the endpoints.
|
||||||
|
public init(_ client: AmiiboClient) {
|
||||||
|
self.client = switch client {
|
||||||
|
case let .mock(mockClient): mockClient
|
||||||
|
case let .live(liveClient): liveClient
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
|
/// Gets a list of amiibo items based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered amiibo items.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
public func getAmiibos(
|
public func getAmiibos(
|
||||||
_ filter: AmiiboFilter = .init()
|
_ filter: AmiiboFilter = .init()
|
||||||
) async throws -> [Amiibo] {
|
) async throws(AmiiboServiceError) -> [Amiibo] {
|
||||||
try await client.getAmiibos(by: filter)
|
try await client.getAmiibos(by: filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a list of amiibo series based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered amiibo series.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
public func getAmiiboSeries(
|
public func getAmiiboSeries(
|
||||||
_ filter: AmiiboSeriesFilter = .init()
|
_ filter: AmiiboSeriesFilter = .init()
|
||||||
) async throws -> [AmiiboSeries] {
|
) async throws(AmiiboServiceError) -> [AmiiboSeries] {
|
||||||
try await client.getAmiiboSeries(by: filter)
|
try await client.getAmiiboSeries(by: filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a list of amiibo types based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered amiibo types.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
public func getAmiiboTypes(
|
public func getAmiiboTypes(
|
||||||
_ filter: AmiiboTypeFilter = .init()
|
_ filter: AmiiboTypeFilter = .init()
|
||||||
) async throws -> [AmiiboType] {
|
) async throws(AmiiboServiceError) -> [AmiiboType] {
|
||||||
try await client.getAmiiboTypes(by: filter)
|
try await client.getAmiiboTypes(by: filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a list of game characters based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered game characters.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
public func getGameCharacters(
|
public func getGameCharacters(
|
||||||
_ filter: GameCharacterFilter = .init()
|
_ filter: GameCharacterFilter = .init()
|
||||||
) async throws -> [GameCharacter] {
|
) async throws(AmiiboServiceError) -> [GameCharacter] {
|
||||||
try await client.getGameCharacters(by: filter)
|
try await client.getGameCharacters(by: filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a list of game series based on a given filter.
|
||||||
|
/// - Parameter filter: A filter to remove unwanted items from the result.
|
||||||
|
/// - Returns: A list of filtered game series.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
public func getGameSeries(
|
public func getGameSeries(
|
||||||
_ filter: GameSeriesFilter = .init()
|
_ filter: GameSeriesFilter = .init()
|
||||||
) async throws -> [GameSeries] {
|
) async throws(AmiiboServiceError) -> [GameSeries] {
|
||||||
try await client.getGameSeries(by: filter)
|
try await client.getGameSeries(by: filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getLastUpdated() async throws -> Date {
|
/// Gets the date when the data was last updated.
|
||||||
|
/// - Returns: A last updated date.
|
||||||
|
/// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result.
|
||||||
|
public func getLastUpdated() async throws(AmiiboServiceError) -> Date {
|
||||||
try await client.getLastUpdated()
|
try await client.getLastUpdated()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-4
@@ -23,10 +23,8 @@ struct AmiiboServiceLiveTests {
|
|||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
|
|
||||||
init() throws {
|
init() {
|
||||||
let client = try AmiiboLiveClient()
|
self.service = .init(.live())
|
||||||
|
|
||||||
self.service = .init(client)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Functions tests
|
// MARK: Functions tests
|
||||||
Reference in New Issue
Block a user