[Setup] Documentation #10

Merged
javier merged 12 commits from setup/documentation into main 2023-04-23 13:16:23 +00:00
14 changed files with 290 additions and 70 deletions

View File

@ -1,3 +1,70 @@
# AmiiboService # AmiiboService: Amiibo API service written in Swift
A description of this package. This package contains a ready-to-use service that can retrieve data as decoded models/entities from any of the [Amiibo API](https://www.amiiboapi.com) available endpoints.
## Installation
It is possible to add this library in your projects either by explicitly add it as a dependency either in a `Package.swift` file or in your Xcode project.
This package has minimum platform requirements that are important to take into account:
* *iOS 13.0 or higher*;
* *macOS 10.15 or higher*;
* *tvOS 13.0 or higher*;
* *watchOS 8.0 or higher*;
### Package file
In the intended `Package.swift` file, it is required to add the following dependency:
```swift
dependencies: [
// ...
.package(url: "https://github.com/rock-n-code/amiibo-service.git", from: "1.0.0")
// ...
],
```
Then it is required to add the package to your target, like this:
```swift
targets: [
.target(
...
dependencies: [
.product(name: "AmiiboService", package: "amiibo-service")
],
...
),
]
```
### Xcode
In an opened Xcode project, it is required to do these steps:
1. click on your Xcode project file to display *Project* and *Targets*;
2. select the project under the *Project* section to show the *Info*, *Build Settings* and *Package Dependencies* in the center menu of the screen;
3. select the *Package Dependencies* to show the defined dependencies of the project;
4. press on the *+* (plus) button to add dependencies to the project;
5. enter the URL`https://github.com/rock-n-code/amiibo-service` into the *Search or Enter Package URL* located in the upper right corner;
6. select the given option;
7. define the dependency rule (the *Up to Next Major Version* option and the *1.0.0* text are recommended);
8. select the target to which the dependency will be applied (if required);
9. wait for the package to be resolved and included in the project;
10. done!
### Other considerations
This library is fully supported on Apple platforms only for the time being: *iOS*, *macOS*, *tvOS*, and *watchOS*. Support for other platforms such as *Linux* or *Windows* might be added in the future, depending on the type of changes those platforms require but this needs to be researched first.
⚠️ Please notice that this library only supports the [Swift Package Manager](https://www.swift.org/package-manager/), and that support for other dependency managers such as *Cocoapods* and *Carthage* is not planned.
## Usage
This package provides an actor called `AmiiboService` which, after is initialised, is responsible for making requests based on a given filter criteria to the remote API, handling the responses, and decoding the retrieved data into models/entities structs, or throws errors if necessary.
It is needless to say, all the necessary filters, models/entities, and enumerations are also provided in this package.
## Further documentation
For further information about the API, please refer to the [Amiibo API documentation](https://www.amiiboapi.com/docs/) available online.

View File

@ -1,4 +1,7 @@
/// This error definitions represents any error happening while the client makes a request to the remote API and handles the respective response, excluding the decoding of the retrieved data into a particular model.
public enum AmiiboClientError: Error { public enum AmiiboClientError: Error {
/// The status code of the response is not the expected one, which is `.ok` (`200`).
case responseCode(Int) case responseCode(Int)
/// The status code of the response was not received at all.
case responseCodeNotFound case responseCodeNotFound
} }

View File

@ -1,3 +1,4 @@
/// This filter provides all the possible parameters (and combinations) available at the remote API applies when filtering amiibos.
public struct AmiiboFilter { public struct AmiiboFilter {
// MARK: Properties // MARK: Properties
@ -14,6 +15,17 @@ public struct AmiiboFilter {
// MARK: Initialisers // MARK: Initialisers
/// Initialises this filter.
/// - Parameters:
/// - id: An amiibo `id` value to match against.
/// - head: An amiibo `head` value to match against.
/// - tail: An amiibo `tail` value to match against.
/// - name: An amiibo `name` value to match against.
/// - type: An amiibo `type` key or name value to match against.
/// - gameSeries: An amiibo `gameSeries` key or name value to match against.
/// - amiiboSeries: An amiibo `amiiboSeries` key or name value to match against.
/// - character: An amiibo `character` key or name value to match against.
/// - showExtras: A ``ShowExtras`` enumeration that indicates whether amiibo extra information need to be retrieved or not.
public init( public init(
id: String? = nil, id: String? = nil,
head: String? = nil, head: String? = nil,
@ -95,10 +107,16 @@ extension AmiiboFilter: Filter {
// MARK: - Enumerations // MARK: - Enumerations
public enum ShowExtras { extension AmiiboFilter {
/// This enumeration indicates if extra information for amiibos need to be retrieved.
public enum ShowExtras {
/// No extra information needs to be retrieved.
case none case none
/// Amiibo games information needs to be retrieved.
case games case games
/// Amiibo games and its usage information needs to be retrieved.
case usage case usage
}
} }
// MARK: - String+Key // MARK: - String+Key

View File

@ -1,3 +1,4 @@
/// This filter provides all the possible parameters (and combinations) available at the remote API applies when filtering amiibos series (``AmiiboSeriesFilter``), amiibo types (``AmiiboTypeFilter``), characters (``CharacterFilter``), or game series (``GameSeriesFilter``).
public struct KeyNameFilter { public struct KeyNameFilter {
// MARK: Properties // MARK: Properties
@ -7,6 +8,10 @@ public struct KeyNameFilter {
// MARK: Initialisers // MARK: Initialisers
/// Initialises this filter.
/// - Parameters:
/// - key: A `key` value to match against.
/// - name: A `name` value to match against.
public init( public init(
key: String? = nil, key: String? = nil,
name: String? = nil name: String? = nil
@ -17,6 +22,20 @@ public struct KeyNameFilter {
} }
// MARK: - Type aliases
/// This filter provides all the possible parameters (and combinations) available at the remote API applies when filtering amiibos series.
public typealias AmiiboSeriesFilter = KeyNameFilter
/// This filter provides all the possible parameters (and combinations) available at the remote API applies when filtering amiibo types.
public typealias AmiiboTypeFilter = KeyNameFilter
/// This filter provides all the possible parameters (and combinations) available at the remote API applies when filtering characters.
public typealias CharacterFilter = KeyNameFilter
/// This filter provides all the possible parameters (and combinations) available at the remote API applies when filtering game series.
public typealias GameSeriesFilter = KeyNameFilter
// MARK: - Filter // MARK: - Filter
extension KeyNameFilter: Filter { extension KeyNameFilter: Filter {
@ -39,13 +58,6 @@ extension KeyNameFilter: Filter {
} }
// MARK: - Type aliases
public typealias AmiiboSeriesFilter = KeyNameFilter
public typealias AmiiboTypeFilter = KeyNameFilter
public typealias CharacterFilter = KeyNameFilter
public typealias GameSeriesFilter = KeyNameFilter
// MARK: - String+Key // MARK: - String+Key
private extension String { private extension String {

View File

@ -1,22 +1,54 @@
/// This model struct represents an amiibo that is retrieved from the respective [remote API endpoint](https://www.amiiboapi.com/docs/#amiibo).
public struct Amiibo { public struct Amiibo {
// MARK: Properties
/// The type the amiibo belongs to.
public let type: String public let type: String
/// The first 8 values of the hexadecimal that identifies the amiibo.
public let head: String public let head: String
/// The last 8 values of the hexadecimal that identifies the amiibo.
public let tail: String public let tail: String
/// The name of the amiibo.
public let name: String public let name: String
/// The character of the amiibo.
public let character: String public let character: String
/// The series the amiibo belongs to.
public let series: String public let series: String
/// The game series of the amiibo.
public let gameSeries: String public let gameSeries: String
/// The URL to an image of the amiibo.
public let image: String public let image: String
/// The release dates of the amiibo (if released) in Australia, Europe, Japan and North America.
public let release: Release public let release: Release
/// The games related to the amiibo, if requested.
public let games: Games? public let games: Games?
} }
// MARK: - Structs // MARK: - Structs
extension Amiibo { extension Amiibo {
/// This model represents the list of games related to a particular amiibo, grouped by system.
public struct Games: Decodable { public struct Games: Decodable {
// MARK: Properties
/// A list of [Nintendo 3DS system](https://en.wikipedia.org/wiki/Nintendo_3DS) games the amiibo can be used with.
public let n3ds: [Game] public let n3ds: [Game]
/// A list of [Nintendo WiiU system](https://en.wikipedia.org/wiki/Wii_U) games the amiibo can be used with.
public let wiiu: [Game] public let wiiu: [Game]
/// /// A list of [Nintendo Switch system](https://en.wikipedia.org/wiki/Nintendo_Switch) games the amiibo can be used with.
public let `switch`: [Game] public let `switch`: [Game]
} }
} }
@ -44,6 +76,9 @@ extension Amiibo: Decodable {
// MARK: Initialisers // MARK: Initialisers
/// Initialises this model by decoding from the given decoder.
/// - Parameter decoder: The decoder to read data from.
/// - Throws: A `DecodingError` error in case the decode failed at decoding data into an expected model type.
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
let games3ds = try container.decodeIfPresent([Game].self, forKey: .games3DS) let games3ds = try container.decodeIfPresent([Game].self, forKey: .games3DS)

View File

@ -0,0 +1,27 @@
extension Amiibo {
/// This model structs represents a game that is related to an amiibo, when requested to the respective [remote API endpoint](https://www.amiiboapi.com/docs/#showGames).
public struct Game {
// MARK: Properties
/// The list of identifiers associated to the game.
public let ids: [String]
/// The name of the game.
public let name: String
/// The list of usages that explains how the amiibo is being used in the game.
public let usage: [Usage]?
}
}
// MARK: - Decodable
extension Amiibo.Game: Decodable {
enum CodingKeys: String, CodingKey {
case ids = "gameID"
case name = "gameName"
case usage = "amiiboUsage"
}
}

View File

@ -0,0 +1,23 @@
extension Amiibo.Game {
/// This model struct represents how an amiibo is used with a particular game, when requested to the respective [remote API endpoint](https://www.amiiboapi.com/docs/#showUsage).
public struct Usage {
// MARK: Properties
/// The explanation on how an amiibo is being used with a particular game.
public let explanation: String
/// A flag that indicates whether an amiibo is only read-only or the game can also write information to the amiibo.
public let isWritable: Bool
}
}
// MARK: - Decodable
extension Amiibo.Game.Usage: Decodable {
enum CodingKeys: String, CodingKey {
case explanation = "Usage"
case isWritable = "write"
}
}

View File

@ -0,0 +1,33 @@
import Foundation
extension Amiibo {
/// This model struct represents a collection of official release dates (if released) of an amiibo in different markets around the world.
public struct Release {
// MARK: Properties
/// The official release date (if released) of an amiibo in Australia.
public let australia: Date?
/// The official release date (if released) of an amiibo in Europe.
public let europe: Date?
/// The official release date (if released) of an amiibo in Japan.
public let japan: Date?
/// The official release date (if released) of an amiibo in North America.
public let america: Date?
}
}
// MARK: - Decodable
extension Amiibo.Release: Decodable {
enum CodingKeys: String, CodingKey {
case australia = "au"
case europe = "eu"
case japan = "jp"
case america = "na"
}
}

View File

@ -1,15 +0,0 @@
public struct Game {
public let ids: [String]
public let name: String
public let usage: [Usage]?
}
// MARK: - Decodable
extension Game: Decodable {
enum CodingKeys: String, CodingKey {
case ids = "gameID"
case name = "gameName"
case usage = "amiiboUsage"
}
}

View File

@ -1,15 +1,30 @@
/// This model is a concrete genetic definition that represents the following models: ``AmiiboSeries``, ``AmiiboType``, ``Character`` and ``GameSeries``.
public struct KeyName { public struct KeyName {
// MARK: Properties
/// The key of the model.
public let key: String public let key: String
public let name: String?
/// The name of the model.
public let name: String
} }
// MARK: - Type aliases
/// This model represents the series an amiibo belongs to.
public typealias AmiiboSeries = KeyName
/// This model represents the type an amiibo belongs to.
public typealias AmiiboType = KeyName
/// This model represents the character an amiibo is associated to.
public typealias Character = KeyName
/// This model represents the games series an amiibo is associated to.
public typealias GameSeries = KeyName
// MARK: - Decodable // MARK: - Decodable
extension KeyName: Decodable {} extension KeyName: Decodable {}
// MARK: - Type aliases
public typealias AmiiboType = KeyName
public typealias AmiiboSeries = KeyName
public typealias GameSeries = KeyName
public typealias Character = KeyName

View File

@ -1,7 +1,13 @@
import Foundation import Foundation
/// This model represents the latest date when the remote API has been updated.
public struct LastUpdated { public struct LastUpdated {
// MARK: Properties
/// The date of the latest update of the remote API.
public let timestamp: Date public let timestamp: Date
} }
// MARK: - Decodable // MARK: - Decodable

View File

@ -1,19 +0,0 @@
import Foundation
public struct Release {
public let australia: Date?
public let europe: Date?
public let japan: Date?
public let america: Date?
}
// MARK: - Decodable
extension Release: Decodable {
enum CodingKeys: String, CodingKey {
case australia = "au"
case europe = "eu"
case japan = "jp"
case america = "na"
}
}

View File

@ -1,13 +0,0 @@
public struct Usage {
public let explanation: String
public let isWritable: Bool
}
// MARK: - Decodable
extension Usage: Decodable {
enum CodingKeys: String, CodingKey {
case explanation = "Usage"
case isWritable = "write"
}
}

View File

@ -1,6 +1,9 @@
import Foundation import Foundation
public struct AmiiboService { /// This service provides the interface to make remote API calls to the [Amiibo API](https://www.amiiboapi.com) and, subsequently, handle its responses.
///
/// Given that this remote service is a read-only API, this service will exclusively return decoded models or entities in cases the requests are successful, or it will throw errors otherwise.
public actor AmiiboService {
// MARK: Properties // MARK: Properties
@ -8,7 +11,9 @@ public struct AmiiboService {
// MARK: Initialisers // MARK: Initialisers
init(configuration: URLSessionConfiguration) { /// Initialises this service.
/// - Parameter configuration: The `URLSessionConfiguration` configuration to use to set this service.
public init(configuration: URLSessionConfiguration) {
self.client = .init(configuration: configuration) self.client = .init(configuration: configuration)
} }
@ -20,6 +25,10 @@ extension AmiiboService: Service {
// MARK: Functions // MARK: Functions
/// Retrieves a list of amiibos from a remote location that matches a given filter criteria.
/// - Parameter filter: A ``AmiiboFilter`` instance that contains the filtering criteria.
/// - Returns: A list of decoded ``Amiibo`` instances that matches the given filter criteria.
/// - Throws: A ``AmiiboClientError`` is thrown in case a request failed, or a `DecodingError` is thrown in case the decoding of some object failed.
public func amiibos( public func amiibos(
filter: AmiiboFilter = .init() filter: AmiiboFilter = .init()
) async throws -> [Amiibo] { ) async throws -> [Amiibo] {
@ -31,6 +40,10 @@ extension AmiiboService: Service {
).items ).items
} }
/// Retrieves a list of amiibo series from a remote location that matches a given filter criteria.
/// - Parameter filter: A ``AmiiboSeriesFilter`` instance that contains the filtering criteria.
/// - Returns: A list of decoded ``AmiiboSeries`` instances that matches the given filter criteria.
/// - Throws: A ``AmiiboClientError`` is thrown in case a request failed, or a `DecodingError` is thrown in case the decoding of some object failed.
public func amiiboSeries( public func amiiboSeries(
filter: AmiiboSeriesFilter = .init() filter: AmiiboSeriesFilter = .init()
) async throws -> [AmiiboSeries] { ) async throws -> [AmiiboSeries] {
@ -42,6 +55,10 @@ extension AmiiboService: Service {
).items ).items
} }
/// Retrieves a list of amiibo types from a remote location that matches a given filter criteria.
/// - Parameter filter: A ``AmiiboTypeFilter`` instance that contains the filtering criteria.
/// - Returns: A list of decoded ``AmiiboType`` instances that matches the given filter criteria.
/// - Throws: A ``AmiiboClientError`` is thrown in case a request failed, or a `DecodingError` is thrown in case the decoding of some object failed.
public func amiiboTypes( public func amiiboTypes(
filter: AmiiboTypeFilter = .init() filter: AmiiboTypeFilter = .init()
) async throws -> [AmiiboType] { ) async throws -> [AmiiboType] {
@ -53,6 +70,10 @@ extension AmiiboService: Service {
).items ).items
} }
/// Retrieves a list of characters from a remote location that matches a given filter criteria.
/// - Parameter filter: A ``CharacterFilter`` instance that contains the filtering criteria.
/// - Returns: A list of decoded ``Character`` instances that matches the given filter criteria.
/// - Throws: A ``AmiiboClientError`` is thrown in case a request failed, or a `DecodingError` is thrown in case the decoding of some object failed.
public func characters( public func characters(
filter: CharacterFilter = .init() filter: CharacterFilter = .init()
) async throws -> [Character] { ) async throws -> [Character] {
@ -64,6 +85,10 @@ extension AmiiboService: Service {
).items ).items
} }
/// Retrieves a list of game series from a remote location that matches a given filter criteria.
/// - Parameter filter: A ``GameSeriesFilter`` instance that contains the filtering criteria.
/// - Returns: A list of decoded ``GameSeries`` instances that matches the given filter criteria.
/// - Throws: A ``AmiiboClientError`` is thrown in case a request failed, or a `DecodingError` is thrown in case the decoding of some object failed.
public func gameSeries( public func gameSeries(
filter: GameSeriesFilter = .init() filter: GameSeriesFilter = .init()
) async throws -> [GameSeries] { ) async throws -> [GameSeries] {
@ -75,6 +100,9 @@ extension AmiiboService: Service {
).items ).items
} }
/// Retrieves the date in which the remote API was last updated.
/// - Returns: A `Date` instance that represents the date in which the remote API was last updated.
/// - Throws: A ``AmiiboClientError`` is thrown in case a request failed, or a `DecodingError` is thrown in case the decoding of some object failed.
public func lastUpdated() async throws -> Date { public func lastUpdated() async throws -> Date {
client.setDateDecodingStrategy(.formatted(.dateAndTime)) client.setDateDecodingStrategy(.formatted(.dateAndTime))