Hi, I am trying to upload a simple png file without success. The request is throwing thread exception because of wrong body type I think.
The endpoint configuration in my repo:
case .register(let verificationId, let verificationCode, let mobilePhone, let deviceName, let userModel, let avatar):
return .init(method: .post,
path: .path(["auth", "register"]),
params: ["mobile_phone": mobilePhone,
"verification_id": verificationId,
"verification_code": verificationCode,
"device_id": deviceName,
"first_name": userModel.firstName,
"last_name": userModel.lastName,
"username": userModel.username,
"avatar": avatar != nil ? MultipartFormDataPartType.url(avatar!) : nil
]
)
This is the caller
func register(mobilePhoneE164: String, verificationId: String, verificationCode: String, user: User, avatar: URL?) async throws {
let deviceUuid = await UIDevice.current.identifierForVendor!.uuidString
let result = try await Client<AuthRepository>()
.request(for: .register(verificationId: verificationId, verificationCode: verificationCode, mobilePhone: mobilePhoneE164, deviceName: deviceUuid, user, avatar: avatar))
.asyncUpload(as: ApiResponse<AccessToken>.self, progressUpdate: nil)
saveToken(accessToken: result.data.accessToken)
}
And finally the exception thrown
2023-08-14 18:34:00.764788+0300 MYPROJECT[43099:16605822] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (__SwiftValue)'
*** First throw call stack:
(
0 CoreFoundation 0x0000000180437330 __exceptionPreprocess + 172
1 libobjc.A.dylib 0x0000000180051274 objc_exception_throw + 56
2 Foundation 0x0000000180c0ed40 _writeJSONValue + 704
3 Foundation 0x0000000180c12bfc ___writeJSONObject_block_invoke + 384
4 libswiftCore.dylib 0x000000018bf3e434 $ss26_SwiftDeferredNSDictionaryC23enumerateKeysAndObjects7options5usingySi_ys9UnmanagedVyyXlG_AHSpys5UInt8VGtXBtFTf4dnn_n + 332
5 libswiftCore.dylib 0x000000018bd43584 $ss26_SwiftDeferredNSDictionaryC23enumerateKeysAndObjects7options5usingySi_ys9UnmanagedVyyXlG_AHSpys5UInt8VGtXBtFTo + 44
6 Foundation 0x0000000180c121a0 _writeJSONObject + 440
7 Foundation 0x0000000180c0ea40 -[_NSJSONWriter dataWithRootObject:options:] + 84
8 Foundation 0x0000000180c1170c +[NSJSONSerialization dataWithJSONObject:options:error:] + 108
9 MYPROJECT 0x0000000104e4303c $sSD12TermiNetworkE10toJSONData10Foundation4DataVSgyKF + 168
10 MYPROJECT 0x0000000104e68938 $s12TermiNetwork20RequestBodyGeneratorC20generateJSONBodyData4with10Foundation0H0VSDySSypSgG_tKFZ + 96
11 MYPROJECT 0x0000000104e87fe8 $s12TermiNetwork7RequestC21addBodyParamsIfNeeded33_C06940D9FEEDCA294CA875886000989FLL04withC06paramsy10Foundation10URLRequestVz_SDySSypSgGSgtKF + 2016
12 MYPROJECT 0x0000000104e87058 $s12TermiNetwork7RequestC02asC010Foundation10URLRequestVyKF + 3176
13 MYPROJECT 0x0000000104e8fc74 $s12TermiNetwork18SessionTaskFactoryC08makeDataD04with17completionHandler9onFailureSo012NSURLSessiongD0CSgAA7RequestC_y10Foundation0G0VSg_So13NSURLResponseCSgtcSgyAP_AA7TNErrorOtcSgtFZ + 344
14 MYPROJECT 0x0000000104e88ab8 $s12TermiNetwork7RequestC011executeDataC8IfNeededyyF + 416
15 MYPROJECT 0x0000000104e43974 $s12TermiNetwork7RequestC7failure15responseHandlerACyAA7TNErrorOc_tF + 156
16 MYPROJECT 0x0000000104e45498 $s12TermiNetwork7RequestC11asyncUpload2as14progressUpdatexxm_ySi_SiSftcSgtYaKSeRzlFxyYaKXEfU_yScCyxs5Error_pGXEfU_ + 524
17 libswift_Concurrency.dylib 0x00000001b1632a3c $ss23withCheckedContinuation8function_xSS_yScCyxs5NeverOGXEtYalFySccyxADGXEfU_Tm + 108
18 libswift_Concurrency.dylib 0x00000001b1632960 $ss31withCheckedThrowingContinuation8function_xSS_yScCyxs5Error_pGXEtYaKlF + 196
19 MYPROJECT 0x0000000104e44e9d $s12TermiNetwork7RequestC11asyncUpload2as14progressUpdatexxm_ySi_SiSftcSgtYaKSeRzlFxyYaKXEfU_TQ1_ + 1
20 MYPROJECT 0x0000000104e451e9 $s12TermiNetwork7RequestC11asyncUpload2as14progressUpdatexxm_ySi_SiSftcSgtYaKSeRzlFxyYaKXEfU_TATQ0_ + 1
21 libswift_Concurrency.dylib 0x00000001b16407a5 $ss27withTaskCancellationHandler9operation8onCancelxxyYaKXE_yyYbXEtYaKlFTQ0_ + 1
22 MYPROJECT 0x0000000104e458a9 $ss27withTaskCancellationHandler9operation8onCancelxxyYaKXE_yyYbXEtYaKlFTwbTQ1_ + 1
23 MYPROJECT 0x0000000104e448f1 $s12TermiNetwork7RequestC11asyncUpload2as14progressUpdatexxm_ySi_SiSftcSgtYaKSeRzlFTQ1_ + 1
24 MYPROJECT 0x0000000104d5e9c9 $s8MYPROJECT11AuthServiceC8register15mobilePhoneE16414verificationId0H4Code4user6avatarySS_S2SAA4UserV10Foundation3URLVSgtYaKFTQ5_ + 1
25 MYPROJECT 0x0000000104d93ac9 $s8MYPROJECT15SignUpViewModelC22validateFormWithServerSbyYaFTQ1_ + 1
26 MYPROJECT 0x0000000104d92f9d $s8MYPROJECT15SignUpViewModelC4saveyyYaFTQ1_ + 1
27 MYPROJECT 0x0000000104d6e351 $s8MYPROJECT10SignUpViewV4bodyQrvg7SwiftUI05TupleD0VyAE0D0PAEE15ignoresSafeArea_5edgesQrAE0jK7RegionsV_AE4EdgeO3SetVtFQOyAE5ColorV_Qo__AiEE7paddingyQrAQ_12CoreGraphics7CGFloatVSgtFQOyAiEE21navigationDestination11isPresented11destinationQrAE7BindingVySbG_qd__yXEtAeHRd__lFQOyAiEE5sheetA_9onDismiss7contentQrA3__yycSgqd__yctAeHRd__lFQOyAE6VStackVyAGyAiEE5frame5width6height9alignmentQrAY_AyE9AlignmentVtFQOyAiEE010foregroundP0yQrASSgFQOyAE5ImageV_Qo__Qo__AiEEAUyQrAQ_AYtFQOyAE4TextV_Qo_A9_yAGyAE6ButtonVyAiEEAUyQrAQ_AYtFQOyAiEEA10_A11_A12_A13_QrAY_AYA15_tFQOyAiEE7overlay_A13_Qrqd___A15_tAeHRd__lFQOyAE5ShapePAEE4fill_5styleQrqd___AE9FillStyleVtAE10ShapeStyleRd__lFQOyAE6CircleV_ASQo__AE5GroupVyAE19_ConditionalContentVyAE6ZStackVyAGyAiEE9clipShape_A31_Qrqd___A33_tAEA28_Rd__lFQOyAA021CompleteProfileAvatarD0V_A36_Qo__AiEE6offset1x1yQrAX_AXtFQOyA26_yAiEEA16_yQrA17_FQOyAiEE4fontyQrAE4FontVSgFQOyA19__Qo__Qo_G_Qo_tGGA19_GGQo__Qo__Qo_G_AiEE8onSubmit2of_QrAE14SubmitTriggersV_yyctFQOyAiEEAUyQrAQ_AYtFQOyAI13FormValidatorE10validationyQrA71_19ValidationContainerVSgFQOyAiEE11submitLabelyQrAE11SubmitLabelVFQOyAiEE12cornerRadius_11antialiasedQrAX_SbtFQOyAiEE10background_0ijK5EdgesQrqd___AQtAEA34_Rd__lFQOyAiEEAUyQrAQ_AYtFQOyAiEEAUyQrAQ_AYtFQOyAiEE27textInputAutocapitalizationyQrAE27TextInputAutocapitalizationVSgFQOyAiEE22autocorrectionDisabledyQrSbFQOyAiEE15textContentTypeyQrSo17UITextContentTypeaSgFQOyAiEE12keyboardTypeyQrSo14UIKeyboardTypeVFQOyAiEE7focused_6equalsQrAE10FocusStateVA1_Vyqd___G_qd__tSHRd__lFQOyAiEEA16_yQrA17_FQOyAE9TextFieldVyA23_G_Qo__AA24CompleteProfileFormFocusOSgQo__Qo__Qo__Qo__Qo__Qo__Qo__ASQo__Qo__Qo__Qo__Qo__Qo_AiEEAUyQrAQ_AYtFQOyAIA71_EA72_yQrA75_FQOyAiEEA76_yQrA78_FQOyAiEEA79__A80_QrAX_SbtFQOyAiEEA81__A82_Qrqd___AQtAEA34_Rd__lFQOyAiEEAUyQrAQ_AYtFQOyAiEEAUyQrAQ_AYtFQOyAiEEA88_yQrA91_FQOyAiEEA83_yQrA86_FQOyAiEEA87_yQrSbFQOyA109__Qo__Qo__Qo__Qo__Qo__ASQo__Qo__Qo__Qo__Qo_A130_tGGAE6SpacerVAA06ButtonD0VtGG_16ExyteMediaPicker11MediaPickerVyAE05EmptyD0VA143_GQo__AA015OtpVerificationD0VQo__Qo_tGyXEfU_A137_yXEfU_yycfU0_yyYaYbcfU_TQ1_ + 1
28 MYPROJECT 0x0000000104d75c9d $s8MYPROJECT10SignUpViewV4bodyQrvg7SwiftUI05TupleD0VyAE0D0PAEE15ignoresSafeArea_5edgesQrAE0jK7RegionsV_AE4EdgeO3SetVtFQOyAE5ColorV_Qo__AiEE7paddingyQrAQ_12CoreGraphics7CGFloatVSgtFQOyAiEE21navigationDestination11isPresented11destinationQrAE7BindingVySbG_qd__yXEtAeHRd__lFQOyAiEE5sheetA_9onDismiss7contentQrA3__yycSgqd__yctAeHRd__lFQOyAE6VStackVyAGyAiEE5frame5width6height9alignmentQrAY_AyE9AlignmentVtFQOyAiEE010foregroundP0yQrASSgFQOyAE5ImageV_Qo__Qo__AiEEAUyQrAQ_AYtFQOyAE4TextV_Qo_A9_yAGyAE6ButtonVyAiEEAUyQrAQ_AYtFQOyAiEEA10_A11_A12_A13_QrAY_AYA15_tFQOyAiEE7overlay_A13_Qrqd___A15_tAeHRd__lFQOyAE5ShapePAEE4fill_5styleQrqd___AE9FillStyleVtAE10ShapeStyleRd__lFQOyAE6CircleV_ASQo__AE5GroupVyAE19_ConditionalContentVyAE6ZStackVyAGyAiEE9clipShape_A31_Qrqd___A33_tAEA28_Rd__lFQOyAA021CompleteProfileAvatarD0V_A36_Qo__AiEE6offset1x1yQrAX_AXtFQOyA26_yAiEEA16_yQrA17_FQOyAiEE4fontyQrAE4FontVSgFQOyA19__Qo__Qo_G_Qo_tGGA19_GGQo__Qo__Qo_G_AiEE8onSubmit2of_QrAE14SubmitTriggersV_yyctFQOyAiEEAUyQrAQ_AYtFQOyAI13FormValidatorE10validationyQrA71_19ValidationContainerVSgFQOyAiEE11submitLabelyQrAE11SubmitLabelVFQOyAiEE12cornerRadius_11antialiasedQrAX_SbtFQOyAiEE10background_0ijK5EdgesQrqd___AQtAEA34_Rd__lFQOyAiEEAUyQrAQ_AYtFQOyAiEEAUyQrAQ_AYtFQOyAiEE27textInputAutocapitalizationyQrAE27TextInputAutocapitalizationVSgFQOyAiEE22autocorrectionDisabledyQrSbFQOyAiEE15textContentTypeyQrSo17UITextContentTypeaSgFQOyAiEE12keyboardTypeyQrSo14UIKeyboardTypeVFQOyAiEE7focused_6equalsQrAE10FocusStateVA1_Vyqd___G_qd__tSHRd__lFQOyAiEEA16_yQrA17_FQOyAE9TextFieldVyA23_G_Qo__AA24CompleteProfileFormFocusOSgQo__Qo__Qo__Qo__Qo__Qo__Qo__ASQo__Qo__Qo__Qo__Qo__Qo_AiEEAUyQrAQ_AYtFQOyAIA71_EA72_yQrA75_FQOyAiEEA76_yQrA78_FQOyAiEEA79__A80_QrAX_SbtFQOyAiEEA81__A82_Qrqd___AQtAEA34_Rd__lFQOyAiEEAUyQrAQ_AYtFQOyAiEEAUyQrAQ_AYtFQOyAiEEA88_yQrA91_FQOyAiEEA83_yQrA86_FQOyAiEEA87_yQrSbFQOyA109__Qo__Qo__Qo__Qo__Qo__ASQo__Qo__Qo__Qo__Qo_A130_tGGAE6SpacerVAA06ButtonD0VtGG_16ExyteMediaPicker11MediaPickerVyAE05EmptyD0VA143_GQo__AA015OtpVerificationD0VQo__Qo_tGyXEfU_A137_yXEfU_yycfU0_yyYaYbcfU_TATQ0_ + 1
29 MYPROJECT 0x0000000104d56e01 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTQ0_ + 1
30 MYPROJECT 0x0000000104d56f41 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTATQ0_ + 1
31 libswift_Concurrency.dylib 0x00000001b1660445 _ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE + 1
)
libc++abi: terminating due to uncaught exception of type NSException
(Recorded stack frame)
#0 0x0000000180437324 in __exceptionPreprocess ()
#1 0x0000000180051274 in objc_exception_throw ()
#2 0x0000000180c0ed40 in _writeJSONValue ()
#3 0x0000000180c12bfc in ___writeJSONObject_block_invoke ()
#4 0x000000018bf3e434 in specialized _SwiftDeferredNSDictionary.enumerateKeysAndObjects(options:using:) ()
#5 0x000000018bd43584 in @objc _SwiftDeferredNSDictionary.enumerateKeysAndObjects(options:using:) ()
#6 0x0000000180c121a0 in _writeJSONObject ()
#7 0x0000000180c0ea40 in -[_NSJSONWriter dataWithRootObject:options:] ()
#8 0x0000000180c1170c in +[NSJSONSerialization dataWithJSONObject:options:error:] ()
#9 0x0000000104e4303c in Dictionary.toJSONData() at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Extensions/Dictionary+Extensions.swift:24
#10 0x0000000104e68938 in static RequestBodyGenerator.generateJSONBodyData(with:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Helpers/RequestBodyGenerators.swift:60
#11 0x0000000104e87fe8 in Request.addBodyParamsIfNeeded(withRequest:params:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Request.swift:291
#12 0x0000000104e87058 in Request.asRequest() at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Request.swift:240
#13 0x0000000104e8fc74 in static SessionTaskFactory.makeDataTask(with:completionHandler:onFailure:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/SessionTaskFactory.swift:35
#14 0x0000000104e88ab8 in Request.executeDataRequestIfNeeded() at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Request.swift:352
#15 0x0000000104e43974 in Request.failure(responseHandler:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Extensions/Operations/Request+DataOperations.swift:37
#16 0x0000000104e45498 in closure #1 in closure #1 in Request.asyncUpload<ฯ_0_0>(as:progressUpdate:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Extensions/Operations/Request+FileOperationsAsync.swift:43
#17 0x00000001b1632a3c in closure #1 in withCheckedContinuation<ฯ_0_0>(function:_:) ()
#18 0x00000001b1632960 in withCheckedThrowingContinuation<ฯ_0_0>(function:_:) ()
#19 0x0000000104e44e9d in closure #1 in Request.asyncUpload<ฯ_0_0>(as:progressUpdate:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Extensions/Operations/Request+FileOperationsAsync.swift:37
#20 0x0000000104e451e9 in partial apply for closure #1 in Request.asyncUpload<ฯ_0_0>(as:progressUpdate:) ()
#21 0x00000001b16407a5 in withTaskCancellationHandler<ฯ_0_0>(operation:onCancel:) ()
#22 0x0000000104e458a9 in withTaskCancellationHandler<ฯ_0_0>(operation:onCancel:) ()
#23 0x0000000104e448f1 in Request.asyncUpload<ฯ_0_0>(as:progressUpdate:) at /myproject/-aorjesgwpwvgdfbmtmzrwsqletef/SourcePackages/checkouts/TermiNetwork/Source/Extensions/Operations/Request+FileOperationsAsync.swift:35
#24 0x0000000104d5e9c9 in AuthService.register(mobilePhoneE164:verificationId:verificationCode:user:avatar:) at /Users/myuser/Developer/MYPROJECT/Code/apps/MYPROJECT/MYPROJECT/Services/AuthService.swift:94
#25 0x0000000104d93ac9 in SignUpViewModel.validateFormWithServer() at /Users/myuser/Developer/MYPROJECT/Code/apps/MYPROJECT/MYPROJECT/ViewModels/Authentication/SignUpViewModel.swift:78
#26 0x0000000104d92f9d in SignUpViewModel.save() at /Users/myuser/Developer/MYPROJECT/Code/apps/MYPROJECT/MYPROJECT/ViewModels/Authentication/SignUpViewModel.swift:61
#27 0x0000000104d6e351 in closure #1 in closure #2 in closure #1 in closure #1 in SignUpView.body.getter at /Users/myuser/Developer/MYPROJECT/Code/apps/MYPROJECT/MYPROJECT/Views/Screens/Authentication/SignUpView.swift:166
#28 0x0000000104d75c9d in partial apply for closure #1 in closure #2 in closure #1 in closure #1 in SignUpView.body.getter ()
#29 0x0000000104d56e01 in thunk for @escaping @callee_guaranteed @Sendable @async () -> (@out ฯ_0_0) ()
#30 0x0000000104d56f41 in partial apply for thunk for @escaping @callee_guaranteed @Sendable @async () -> (@out ฯ_0_0) ()
#31 0x00000001b1660445 in completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) ()
I am thinking it's because of wrong body type since the request is trying to write json output while the avatar param is MultiPart
Once this is resolved I will try to find time to create PR with documentation on uploading
EDIT:
case .register(let verificationId, let verificationCode, let mobilePhone, let deviceName, let userModel, let avatar):
let config = Configuration()
config.requestBodyType = .multipartFormData(boundary: UUID().uuidString)
return .init(method: .post,
path: .path(["auth", "register"]),
params: ["mobile_phone": MultipartFormDataPartType.value(value: mobilePhone),
"verification_id": MultipartFormDataPartType.value(value: verificationId),
"verification_code": MultipartFormDataPartType.value(value: verificationCode),
"device_id": MultipartFormDataPartType.value(value: deviceName),
"first_name": MultipartFormDataPartType.value(value: userModel.firstName),
"last_name": MultipartFormDataPartType.value(value: userModel.lastName),
"username": MultipartFormDataPartType.value(value: userModel.username),
"avatar": avatar != nil ? MultipartFormDataPartType.url(avatar!) : nil
],
configuration: config
)
By explicitly configuring the body as multipart its working fine. But if verbose is enabled it does not work in either way so I think the issue is in asyncUpload() not setting the appropriate body type.
EDIT 1:
When no file is passed even though the body is same as with avatar the request is empty.