swiftdata-structuresenums

Swift data structure reverse engineering


Given the following definition of ApiError:

struct ApiError: Error {

    var statusCode: Int!
    let errorCode: String
    var message: String

    init(statusCode: Int = 0, errorCode: String, message: String) {
        self.statusCode = statusCode
        self.errorCode = errorCode
        self.message = message
    }

    var errorCodeNumber: String {
        let numberString = errorCode.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
        return numberString
    }

    private enum CodingKeys: String, CodingKey {
        case errorCode
        case message
    }
}

extension ApiError: Decodable {

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        errorCode = try container.decode(String.self, forKey: .errorCode)
        message = try container.decode(String.self, forKey: .message)
    }
}

and the following code snippet:

switch response.statusCode {
        case 200...299:
            do {
                return try JSONDecoder().decode(T.self, from: data)
            } catch {
                throw ApiError(
                    errorCode: KnownErrors.ErrorCode.decodingDataError.rawValue,
                    message: "decoding error"
                )
            }
        default:
            guard let decodedError = try? JSONDecoder().decode(ApiError.self, from: data) else {
                throw ApiError(
                    statusCode: response.statusCode,
                    errorCode: "0",
                    message: "Unknown backend error"
                )
            }
            if response.statusCode == 403 && decodedError.errorCode == KnownErrors.ErrorCode.expiredToken.rawValue {
                //exit session
            }
            throw ApiError(
                statusCode: response.statusCode,
                errorCode: decodedError.errorCode,
                message: decodedError.message
            )
        }

What would the KnownErrors and ErrorCode data structures look like? I'm confused by KnownErrors.ErrorCode and I've tried various combinations of structs and enums but nothing seems to be working out.


Solution

  • This looks like a nested type. ErrorCode is nested inside KnownErrors.

    Judging from the context, ErrorCode is likely to be an enum with a raw value type of String.

    KnownErrors could be any type that can have nested types - enum, class, struct, actor, and so on. Judging from the context, KnownErrors likely acts as a namespace of sorts, so that the name ErrorCode doesn't conflict with other types with the same name, similar to the purpose of the Tips enum in TipKit. Because of this, I would choose to declare it as an enum with no cases, so that it is uninhabited. It is just a namespace after all.

    enum KnownErrors {
        enum ErrorCode: String {
            case decodingDataError, expiredToken
        }
    }
    

    Note that this is, in my opinion, the most sensible way to declare KnownErrors and ErrorCode for the given code to compile. It is far from the only way. For all I know, ErrorCode could be a static property of KnownErrors, and decodingDataError could be an instance property of whatever type ErrorCode is of.