Triton/Packages/AccountUpdate/Sources/AccountUpdateNetworkService/AccountUpdateNetworkService.swift
Otavio Cordeiro 853a1e1e8b Handle optional account name with "Anonymous" fallback
Make account name optional in API response and map nil/empty values to
"Anonymous" at the network boundary. This ensures users who haven't set
their name can remain anonymous while keeping the name non-optional in
domain and UI layers.

- Make AccountInformationResponse.Response.name optional (String?)
- Add mapping logic in AccountUpdateNetworkService to default nil/empty
  names to "Anonymous"
- Preserve non-optional String type in AccountResponse and
  Account models
- No changes required in UI or persistence layers
2025-12-17 13:39:39 +01:00

109 lines
3.9 KiB
Swift

import Foundation
import MicroClient
import OMGAPI
/// A protocol for network operations related to account information updates.
///
/// This protocol defines the interface for fetching account information and associated
/// addresses from the remote server. It provides the network layer functionality needed
/// to keep local account information synchronized with the server state.
///
/// The protocol supports fetching both core account information (name, email, creation date)
/// and associated addresses (domains) with their registration and expiration details.
/// This information is typically used to populate user profile displays and manage
/// domain/address ownership information.
public protocol AccountUpdateNetworkServiceProtocol: Sendable {
/// Fetches the current account information from the server.
///
/// This method retrieves the authenticated user's account details including
/// their name, email address, and account creation date. The information
/// is fetched from the server's account information endpoint.
///
/// - Returns: An `AccountResponse` containing the user's account information.
/// - Throws: Network errors, authentication errors, or API errors if the fetch fails.
func fetchAccount() async throws -> AccountResponse
/// Fetches all addresses associated with the current account.
///
/// This method retrieves the list of addresses that are registered
/// to the authenticated user's account. Each address includes registration
/// and expiration dates, providing complete ownership information.
///
/// - Returns: An array of `AddressResponse` objects representing the user's addresses.
/// - Throws: Network errors, authentication errors, or API errors if the fetch fails.
func fetchAddresses() async throws -> [AddressResponse]
}
actor AccountUpdateNetworkService: AccountUpdateNetworkServiceProtocol {
// MARK: - Properties
private let networkClient: NetworkClientProtocol
// MARK: - Lifecycle
init(
networkClient: NetworkClientProtocol
) {
self.networkClient = networkClient
}
// MARK: - Public
func fetchAccount() async throws -> AccountResponse {
let accountResponse = try await networkClient.run(
AccountRequestFactory.makeAccountInformationRequest()
)
return AccountResponse(
response: accountResponse.value.response
)
}
func fetchAddresses() async throws -> [AddressResponse] {
let addressesResponse = try await networkClient.run(
AccountRequestFactory.makeAccountAddressesRequest()
)
return addressesResponse.value.response.map(AddressResponse.init)
}
}
// MARK: - Private
private extension AccountResponse {
/// Initializes the `AccountResponse` model from the network response
/// model, so that the client doesn't depend on network models.
///
/// If the name from the API response is `nil` or empty, it defaults to "Anonymous"
/// to ensure all layers of the application work with a non-optional name value.
///
/// - Parameter response: The network model to be mapped.
init(
response: AccountInformationResponse.Response
) {
if let responseName = response.name, !responseName.isEmpty {
name = responseName
} else {
name = "Anonymous"
}
email = response.email
unixEpochTime = response.created.unixEpochTime
}
}
private extension AddressResponse {
/// Initializes the `AddressResponse` model from the network response
/// model, so that the client doesn't depend on network models.
/// - Parameter response: The network model to be mapped.
init(
response: AccountAddressesResponse.AccountAddressResponse
) {
address = response.address
unixEpochTime = response.registration.unixEpochTime
expireUnixEpochTime = response.expiration.unixEpochTime
}
}