Skip to content

Commit 1c82538

Browse files
authored
[Auth] Migrate setFields behavior to Response initializer (#14023)
1 parent f96b347 commit 1c82538

27 files changed

+76
-73
lines changed

FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -251,66 +251,74 @@ class AuthBackend: AuthBackendProtocol {
251251
}
252252
dictionary = decodedDictionary
253253

254-
var response = T.Response()
254+
let responseResult = Result {
255+
try T.Response(dictionary: dictionary)
256+
}
255257

256258
// At this point we either have an error with successfully decoded
257259
// details in the body, or we have a response which must pass further
258260
// validation before we know it's truly successful. We deal with the
259261
// case where we have an error with successfully decoded error details
260262
// first:
261-
if error != nil {
262-
if let errorDictionary = dictionary["error"] as? [String: AnyHashable] {
263-
if let errorMessage = errorDictionary["message"] as? String {
264-
if let clientError = Self.clientError(
265-
withServerErrorMessage: errorMessage,
266-
errorDictionary: errorDictionary,
267-
response: response,
268-
error: error
269-
) {
270-
throw clientError
263+
switch responseResult {
264+
case let .success(response):
265+
try propagateError(error, dictionary: dictionary, response: response)
266+
// In case returnIDPCredential of a verifyAssertion request is set to
267+
// @YES, the server may return a 200 with a response that may contain a
268+
// server error.
269+
if let verifyAssertionRequest = request as? VerifyAssertionRequest {
270+
if verifyAssertionRequest.returnIDPCredential {
271+
if let errorMessage = dictionary["errorMessage"] as? String {
272+
if let clientError = Self.clientError(
273+
withServerErrorMessage: errorMessage,
274+
errorDictionary: dictionary,
275+
response: response,
276+
error: error
277+
) {
278+
throw clientError
279+
}
271280
}
272281
}
273-
// Not a message we know, return the message directly.
274-
throw AuthErrorUtils.unexpectedErrorResponse(
275-
deserializedResponse: errorDictionary,
276-
underlyingError: error
277-
)
278282
}
279-
// No error message at all, return the decoded response.
283+
return response
284+
case let .failure(failure):
285+
try propagateError(error, dictionary: dictionary, response: nil)
280286
throw AuthErrorUtils
281-
.unexpectedErrorResponse(deserializedResponse: dictionary, underlyingError: error)
287+
.RPCResponseDecodingError(deserializedResponse: dictionary, underlyingError: failure)
282288
}
289+
}
283290

284-
// Finally, we try to populate the response object with the JSON values.
285-
do {
286-
try response.setFields(dictionary: dictionary)
287-
} catch {
288-
throw AuthErrorUtils
289-
.RPCResponseDecodingError(deserializedResponse: dictionary, underlyingError: error)
291+
private func propagateError(_ error: Error?, dictionary: [String: AnyHashable],
292+
response: AuthRPCResponse?) throws {
293+
guard let error else {
294+
return
290295
}
291-
// In case returnIDPCredential of a verifyAssertion request is set to
292-
// @YES, the server may return a 200 with a response that may contain a
293-
// server error.
294-
if let verifyAssertionRequest = request as? VerifyAssertionRequest {
295-
if verifyAssertionRequest.returnIDPCredential {
296-
if let errorMessage = dictionary["errorMessage"] as? String {
297-
if let clientError = Self.clientError(
298-
withServerErrorMessage: errorMessage,
299-
errorDictionary: dictionary,
300-
response: response,
301-
error: error
302-
) {
303-
throw clientError
304-
}
296+
297+
if let errorDictionary = dictionary["error"] as? [String: AnyHashable] {
298+
if let errorMessage = errorDictionary["message"] as? String {
299+
if let clientError = Self.clientError(
300+
withServerErrorMessage: errorMessage,
301+
errorDictionary: errorDictionary,
302+
response: response,
303+
error: error
304+
) {
305+
throw clientError
305306
}
306307
}
308+
// Not a message we know, return the message directly.
309+
throw AuthErrorUtils.unexpectedErrorResponse(
310+
deserializedResponse: errorDictionary,
311+
underlyingError: error
312+
)
307313
}
308-
return response
314+
// No error message at all, return the decoded response.
315+
throw AuthErrorUtils
316+
.unexpectedErrorResponse(deserializedResponse: dictionary, underlyingError: error)
309317
}
310318

311319
private static func clientError(withServerErrorMessage serverErrorMessage: String,
312320
errorDictionary: [String: Any],
313-
response: AuthRPCResponse,
321+
response: AuthRPCResponse?,
314322
error: Error?) -> Error? {
315323
let split = serverErrorMessage.split(separator: ":")
316324
let shortErrorMessage = split.first?.trimmingCharacters(in: .whitespacesAndNewlines)

FirebaseAuth/Sources/Swift/Backend/AuthRPCResponse.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,11 @@
1515
import Foundation
1616

1717
protocol AuthRPCResponse: Sendable {
18-
/// Bare initializer for a response.
19-
init()
20-
21-
/// Sets the response instance from the decoded JSON response.
18+
/// Initializes the response instance from the decoded JSON response.
2219
/// - Parameter dictionary: The dictionary decoded from HTTP JSON response.
2320
/// - Parameter error: An out field for an error which occurred constructing the request.
2421
/// - Returns: Whether the operation was successful or not.
25-
mutating func setFields(dictionary: [String: AnyHashable]) throws
22+
init(dictionary: [String: AnyHashable]) throws
2623

2724
/// This optional method allows response classes to create client errors given a short error
2825
/// message and a detail error message from the server.

FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct CreateAuthURIResponse: AuthRPCResponse {
3535
/// A list of sign-in methods available for the passed identifier.
3636
var signinMethods: [String] = []
3737

38-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
38+
init(dictionary: [String: AnyHashable]) throws {
3939
providerID = dictionary["providerId"] as? String
4040
authURI = dictionary["authUri"] as? String
4141
registered = dictionary["registered"] as? Bool ?? false

FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ import Foundation
1818
///
1919
/// See https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount
2020
struct DeleteAccountResponse: AuthRPCResponse {
21-
mutating func setFields(dictionary: [String: AnyHashable]) throws {}
21+
init(dictionary: [String: AnyHashable]) throws {}
2222
}

FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct EmailLinkSignInResponse: AuthRPCResponse, AuthMFAResponse {
4040
/// Info on which multi-factor authentication providers are enabled.
4141
private(set) var mfaInfo: [AuthProtoMFAEnrollment]?
4242

43-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
43+
init(dictionary: [String: AnyHashable]) throws {
4444
email = dictionary["email"] as? String
4545
idToken = dictionary["idToken"] as? String
4646
isNewUser = dictionary["isNewUser"] as? Bool ?? false

FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ struct GetAccountInfoResponse: AuthRPCResponse {
139139
/// The requested users' profiles.
140140
var users: [Self.User]?
141141

142-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
142+
init(dictionary: [String: AnyHashable]) throws {
143143
guard let usersData = dictionary["users"] as? [[String: AnyHashable]] else {
144144
throw AuthErrorUtils.unexpectedResponse(deserializedResponse: dictionary)
145145
}

FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ private let kOOBCodeKey = "oobCode"
1919
struct GetOOBConfirmationCodeResponse: AuthRPCResponse {
2020
var OOBCode: String?
2121

22-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
22+
init(dictionary: [String: AnyHashable]) throws {
2323
OOBCode = dictionary[kOOBCodeKey] as? String
2424
}
2525
}

FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct GetProjectConfigResponse: AuthRPCResponse {
1919

2020
var authorizedDomains: [String]?
2121

22-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
22+
init(dictionary: [String: AnyHashable]) throws {
2323
projectID = dictionary["projectId"] as? String
2424
if let authorizedDomains = dictionary["authorizedDomains"] as? String,
2525
let data = authorizedDomains.data(using: .utf8) {

FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct GetRecaptchaConfigResponse: AuthRPCResponse {
1818
private(set) var recaptchaKey: String?
1919
private(set) var enforcementState: [[String: String]]?
2020

21-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
21+
init(dictionary: [String: AnyHashable]) throws {
2222
recaptchaKey = dictionary["recaptchaKey"] as? String
2323
enforcementState = dictionary["recaptchaEnforcementState"] as? [[String: String]]
2424
}

FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentResponse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct FinalizeMFAEnrollmentResponse: AuthRPCResponse {
2121
private(set) var phoneSessionInfo: AuthProtoFinalizeMFAPhoneResponseInfo?
2222
private(set) var totpSessionInfo: AuthProtoFinalizeMFATOTPEnrollmentResponseInfo?
2323

24-
mutating func setFields(dictionary: [String: AnyHashable]) throws {
24+
init(dictionary: [String: AnyHashable]) throws {
2525
idToken = dictionary["idToken"] as? String
2626
refreshToken = dictionary["refreshToken"] as? String
2727

0 commit comments

Comments
 (0)