I am trying to write a simple function handling authentication POST
requests that return JWT tokens.
My LoopBack 4 API returns the token as a JSON packet in the following format:
{ "token": "my.jwt.token" }
In case of an error, the following gets returned instead:
{
"error": {
"statusCode": 401,
"name": "UnauthorizedError",
"message": "Invalid email or password."
}
}
As you can see, these types are completely different, they don't have any common properties.
I've defined the following Swift structures to represent them:
// Success
struct Token: Decodable {
let token: String
}
// Error
struct TokenError: Decodable {
let error: ApiError
}
struct ApiError: Decodable {
let statusCode: Int
let name: String
let message: String
}
The signature of the authentication request that returns Swift Generics:
@available(iOS 15.0.0, *)
func requestToken<T: Decodable>(_ user: String, _ password: String) async throws -> T
I've been trying to unit test this function but Swift requires me to declare the type of the result up front:
let result: Token = try await requestToken(login, password)
This works perfectly fine for the happy path but if the authentication is unsuccessful, a The data couldn’t be read because it is missing.
error gets thrown. I can certainly do-catch it but I haven't been able to cast the result to my TokenError
type in order to access its properties.
I have come across a few threads on StackOverflow where the general advice is to represent the success and error types by a common protocol but I've had no luck with that either due to a conflict with the Decodable
protocol that the response types already conform to.
So the question is whether it is possible to work with both success and error result
variables returned by my requestToken
function.