@@ -441,13 +441,10 @@ enum FunctionsConstants {
441
441
timeoutInterval: timeout)
442
442
let fetcher = fetcherService. fetcher ( with: request)
443
443
444
- // Encode the data in the body.
445
- let data = data ?? NSNull ( )
446
- // Force unwrap to match the old invalid argument thrown.
447
- let encoded = try ! serializer. encode ( data)
448
- let body = [ " data " : encoded]
449
-
450
444
do {
445
+ let data = data ?? NSNull ( )
446
+ let encoded = try serializer. encode ( data)
447
+ let body = [ " data " : encoded]
451
448
let payload = try JSONSerialization . data ( withJSONObject: body)
452
449
fetcher. bodyData = payload
453
450
} catch {
@@ -488,79 +485,76 @@ enum FunctionsConstants {
488
485
fetcher. allowedInsecureSchemes = [ " http " ]
489
486
}
490
487
491
- fetcher. beginFetch { data, error in
492
- // If there was an HTTP error, convert it to our own error domain.
493
- var localError : Error ?
494
- if let error = error as NSError ? {
495
- if error. domain == kGTMSessionFetcherStatusDomain {
496
- localError = FunctionsErrorForResponse (
497
- status: error. code,
498
- body: data,
499
- serializer: self . serializer
500
- )
501
- } else if error. domain == NSURLErrorDomain, error. code == NSURLErrorTimedOut {
502
- localError = FunctionsErrorCode . deadlineExceeded. generatedError ( userInfo: nil )
503
- }
504
- // If there was an error, report it to the user and stop.
505
- if let localError {
506
- completion ( . failure( localError) )
507
- } else {
508
- completion ( . failure( error) )
509
- }
510
- return
511
- } else {
512
- // If there wasn't an HTTP error, see if there was an error in the body.
513
- if let bodyError = FunctionsErrorForResponse (
514
- status: 200 ,
515
- body: data,
516
- serializer: self . serializer
517
- ) {
518
- completion ( . failure( bodyError) )
519
- return
520
- }
521
- }
522
-
523
- // Porting: this check is new since we didn't previously check if `data` was nil.
524
- guard let data = data else {
525
- completion ( . failure( FunctionsErrorCode . internal. generatedError ( userInfo: nil ) ) )
526
- return
527
- }
528
-
529
- let responseJSONObject : Any
488
+ fetcher. beginFetch { [ self ] data, error in
489
+ let result : Result < HTTPSCallableResult , any Error >
530
490
do {
531
- responseJSONObject = try JSONSerialization . jsonObject ( with: data)
491
+ let data = try responseData ( data: data, error: error)
492
+ let json = try responseDataJSON ( from: data)
493
+ // TODO: Refactor `decode(_:)` so it either returns a non-optional object or throws
494
+ let payload = try serializer. decode ( json)
495
+ // TODO: Remove `as Any` once `decode(_:)` is refactored
496
+ result = . success( HTTPSCallableResult ( data: payload as Any ) )
532
497
} catch {
533
- completion ( . failure( error) )
534
- return
498
+ result = . failure( error)
535
499
}
536
500
537
- guard let responseJSON = responseJSONObject as? NSDictionary else {
538
- let userInfo = [ NSLocalizedDescriptionKey: " Response was not a dictionary. " ]
539
- completion ( . failure( FunctionsErrorCode . internal. generatedError ( userInfo: userInfo) ) )
540
- return
501
+ DispatchQueue . main. async {
502
+ completion ( result)
541
503
}
504
+ }
505
+ }
542
506
543
- // TODO(klimt): Allow "result" instead of "data" for now, for backwards compatibility.
544
- let dataJSON = responseJSON [ " data " ] ?? responseJSON [ " result " ]
545
- guard let dataJSON = dataJSON as AnyObject ? else {
546
- let userInfo = [ NSLocalizedDescriptionKey: " Response is missing data field. " ]
547
- completion ( . failure( FunctionsErrorCode . internal. generatedError ( userInfo: userInfo) ) )
548
- return
507
+ private func responseData( data: Data ? , error: ( any Error ) ? ) throws -> Data {
508
+ // Case 1: `error` is not `nil` -> always throws
509
+ if let error = error as NSError ? {
510
+ let localError : ( any Error ) ?
511
+ if error. domain == kGTMSessionFetcherStatusDomain {
512
+ localError = FunctionsErrorForResponse (
513
+ status: error. code,
514
+ body: data,
515
+ serializer: serializer
516
+ )
517
+ } else if error. domain == NSURLErrorDomain, error. code == NSURLErrorTimedOut {
518
+ localError = FunctionsErrorCode . deadlineExceeded. generatedError ( userInfo: nil )
519
+ } else {
520
+ localError = nil
549
521
}
550
522
551
- let resultData : Any ?
552
- do {
553
- resultData = try self . serializer . decode ( dataJSON )
554
- } catch {
555
- completion ( . failure ( error ) )
556
- return
557
- }
523
+ throw localError ?? error
524
+ }
525
+
526
+ // Case 2: `data` is `nil` -> always throws
527
+ guard let data else {
528
+ throw FunctionsErrorCode . internal . generatedError ( userInfo : nil )
529
+ }
558
530
559
- // TODO: Force unwrap... gross
560
- let result = HTTPSCallableResult ( data: resultData!)
561
- // TODO: This copied comment appears to be incorrect - it's impossible to have a nil callable result
562
- // If there's no result field, this will return nil, which is fine.
563
- completion ( . success( result) )
531
+ // Case 3: `data` is not `nil` but might specify a custom error -> throws conditionally
532
+ if let bodyError = FunctionsErrorForResponse (
533
+ status: 200 ,
534
+ body: data,
535
+ serializer: serializer
536
+ ) {
537
+ throw bodyError
564
538
}
539
+
540
+ // Case 4: `error` is `nil`; `data` is not `nil`; `data` doesn’t specify an error -> OK
541
+ return data
542
+ }
543
+
544
+ private func responseDataJSON( from data: Data ) throws -> Any {
545
+ let responseJSONObject = try JSONSerialization . jsonObject ( with: data)
546
+
547
+ guard let responseJSON = responseJSONObject as? NSDictionary else {
548
+ let userInfo = [ NSLocalizedDescriptionKey: " Response was not a dictionary. " ]
549
+ throw FunctionsErrorCode . internal. generatedError ( userInfo: userInfo)
550
+ }
551
+
552
+ // `result` is checked for backwards compatibility:
553
+ guard let dataJSON = responseJSON [ " data " ] ?? responseJSON [ " result " ] else {
554
+ let userInfo = [ NSLocalizedDescriptionKey: " Response is missing data field. " ]
555
+ throw FunctionsErrorCode . internal. generatedError ( userInfo: userInfo)
556
+ }
557
+
558
+ return dataJSON
565
559
}
566
560
}
0 commit comments