From 43f47b0648ad5a2a6829bce44cdb16ee71b98edd Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 26 Jul 2026 01:42:47 +0200 Subject: [PATCH] Refactored the Amiibo Live client in the library target to reduce boilerplate. --- .../Public/Clients/AmiiboLiveClient.swift | 95 +++++++++---------- 1 file changed, 43 insertions(+), 52 deletions(-) diff --git a/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift b/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift index c5ff26d..ecac350 100644 --- a/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift +++ b/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift @@ -130,10 +130,8 @@ private extension AmiiboLiveClient { func fetchAmiibos( _ filter: AmiiboFilter ) async throws(AmiiboServiceError) -> [Amiibo] { - let response: Operations.getAmiibos.Output - - do { - response = try await client.getAmiibos(.init(query: .init( + let response = try await perform { + try await client.getAmiibos(.init(query: .init( id: filter.identifier, head: filter.head, tail: filter.tail, @@ -145,8 +143,6 @@ private extension AmiiboLiveClient { showgames: filter.showGames, showusage: filter.showUsage ))) - } catch { - try handle(error: error) } switch response { @@ -182,15 +178,11 @@ private extension AmiiboLiveClient { func fetchAmiiboSeries( _ filter: AmiiboSeriesFilter ) async throws(AmiiboServiceError) -> [AmiiboSeries] { - let response: Operations.getAmiiboSeries.Output - - do { - response = try await client.getAmiiboSeries(.init(query: .init( + let response = try await perform { + try await client.getAmiiboSeries(.init(query: .init( key: filter.key, name: filter.name ))) - } catch { - try handle(error: error) } switch response { @@ -199,11 +191,9 @@ private extension AmiiboLiveClient { case let .json(output): switch output.amiibo { case let .AmiiboSeries(payload): - return [AmiiboSeries(payload.value1)] + return makeModels(from: [payload.value1]) case let .case2(list): - return list - .map { AmiiboSeries($0.value1) } - .sorted { $0.key < $1.key } + return makeModels(from: list.map(\.value1)) } } case .badRequest: @@ -224,15 +214,11 @@ private extension AmiiboLiveClient { func fetchAmiiboTypes( _ filter: AmiiboTypeFilter ) async throws(AmiiboServiceError) -> [AmiiboType] { - let response: Operations.getAmiiboTypes.Output - - do { - response = try await client.getAmiiboTypes(.init(query: .init( + let response = try await perform { + try await client.getAmiiboTypes(.init(query: .init( key: filter.key, name: filter.name ))) - } catch { - try handle(error: error) } switch response { @@ -241,11 +227,9 @@ private extension AmiiboLiveClient { case let .json(output): switch output.amiibo { case let .AmiiboType(payload): - return [AmiiboType(payload.value1)] + return makeModels(from: [payload.value1]) case let .case2(list): - return list - .map { AmiiboType($0.value1) } - .sorted { $0.key < $1.key } + return makeModels(from: list.map(\.value1)) } } case .badRequest: @@ -266,15 +250,11 @@ private extension AmiiboLiveClient { func fetchGameCharacters( _ filter: GameCharacterFilter ) async throws(AmiiboServiceError) -> [GameCharacter] { - let response: Operations.getGameCharacters.Output - - do { - response = try await client.getGameCharacters(.init(query: .init( + let response = try await perform { + try await client.getGameCharacters(.init(query: .init( key: filter.key, name: filter.name ))) - } catch { - try handle(error: error) } switch response { @@ -283,11 +263,9 @@ private extension AmiiboLiveClient { case let .json(output): switch output.amiibo { case let .GameCharacter(payload): - return [GameCharacter(payload.value1)] + return makeModels(from: [payload.value1]) case let .case2(list): - return list - .map { GameCharacter($0.value1) } - .sorted { $0.key < $1.key } + return makeModels(from: list.map(\.value1)) } } case .badRequest: @@ -308,15 +286,11 @@ private extension AmiiboLiveClient { func fetchGameSeries( _ filter: GameSeriesFilter ) async throws(AmiiboServiceError) -> [GameSeries] { - let response: Operations.getGameSeries.Output - - do { - response = try await client.getGameSeries(.init(query: .init( + let response = try await perform { + try await client.getGameSeries(.init(query: .init( key: filter.key, name: filter.name ))) - } catch { - try handle(error: error) } switch response { @@ -325,11 +299,9 @@ private extension AmiiboLiveClient { case let .json(output): switch output.amiibo { case let .GameSeries(payload): - return [GameSeries(payload.value1)] + return makeModels(from: [payload.value1]) case let .case2(list): - return list - .map { GameSeries($0.value1) } - .sorted { $0.key < $1.key } + return makeModels(from: list.map(\.value1)) } } case .badRequest: @@ -347,12 +319,8 @@ private extension AmiiboLiveClient { /// - Returns: A fetched last updated date. /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. func fetchLastUpdated() async throws(AmiiboServiceError) -> Date { - let response: Operations.getLastUpdated.Output - - do { - response = try await client.getLastUpdated() - } catch { - try handle(error: error) + let response = try await perform { + try await client.getLastUpdated() } switch response { @@ -368,6 +336,29 @@ private extension AmiiboLiveClient { } } + /// Performs an API call, mapping any error thrown by the underlying client to an ``AmiiboServiceError`` error. + /// - Parameter operation: A closure that performs the API call. + /// - Returns: The output of the performed API call. + /// - Throws: An ``AmiiboServiceError`` error in case the API call failed. + func perform( + _ operation: () async throws -> Output + ) async throws(AmiiboServiceError) -> Output { + do { + return try await operation() + } catch { + try handle(error: error) + } + } + + /// Maps a list of key-name tuples into a sorted list of models. + /// - Parameter tuples: A list of tuples to map into models. + /// - Returns: A list of models sorted by their keys in ascending order. + func makeModels(from tuples: [Components.Schemas.Tuple]) -> [Model] { + tuples + .map { Model($0) } + .sorted { $0.key < $1.key } + } + /// Maps a given error to an ``AmiiboServiceError`` error. /// - Parameter error: An error to map. /// - Throws: An ``AmiiboServiceError`` error that corresponds to the given error.