Reputation: 2982
I'm trying to make a simple sign-in request to a backend. The backend returns a JSON object consisting of a status code, a string message every time, and an access token only if the sign-in was successful.
For that, I have created the following struct
:
struct AuthResponse: Decodable {
enum CodingKeys: String, CodingKey {
case code, message
case accessToken = "access_token"
}
let code: Int, message: String, accessToken: String?
}
When the sign-in is unsuccessful and an access token is not sent by the server, the AuthResponse
object manages to decode properly, with nil
for the accessToken
property, just as I expect it to. For example, the decode is successful for the following response:
code = 400;
message = "User not registered";
But for a response with an access token, like this one:
"access_token" = TheAccessToken;
code = 200;
message = "Login successfully";
The AuthResponse
object does not fails to decode.
Why does this happen? Does that have to do with the fact that the accessToken
property is optional? I have also tried overriding the decoding initializer and implementing a decodeIfPresent(_:forKey:)
and unwrapping the property but both didn't seem to help.
Thanks in advance.
Upvotes: 0
Views: 1087
Reputation: 285069
The code must not fail with your given information.
Please print the error
instance in the catch
block and add it to your question.
Nevertheless a sophisticated alternative – without any optional – is an enum with associated types. It returns the token on success and the code and message on failure
enum AuthResponse: Decodable {
case success(String), failure(Int, String)
private enum CodingKeys : String, CodingKey { case code, message, accessToken = "access_token" }
init(from decoder : Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
let code = try container.decode(Int.self, forKey: .code)
if code == 200 {
let token = try container.decode(String.self, forKey: .accessToken)
self = .success(token)
} else {
let message = try container.decode(String.self, forKey: .message)
self = .failure(code, message)
}
}
}
}
and use it
let result = try JSONDecoder().decode(AuthResponse.self, from: data)
switch result {
case .success(let token): print(token)
case .failure(let code, let message): print(code, message)
}
Upvotes: 2