I am currently refactoring the signup process for a sports media app in SwiftUI and having issues trying to have it save data associated with the new user to the backend (comprised of a mix of Firebase and a custom backend) via a signup function in an AuthService class. Whenever I enter the required info to create an account (email, username, password, etc.), I get the following errors
Error: The data couldn’t be read because it is missing. Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "user", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"user\", intValue: nil) (\"user\").", underlyingError: nil))
Here is all the relevant code:
// // SignUpView.swift // uSTADIUM // // Created by Omar Hegazy on 9/2/23. // Copyright © 2023 uSTADIUM. All rights reserved. // import SwiftUI struct SignUpView: View { @State private var name = "" @State private var email = "" @State private var username = "" @State private var password = "" @State private var phoneNumber = "" @State private var isNavigatingToInterests = false @ObservedObject var signupState: SignupState @Environment(\.presentationMode) var presentationMode @Environment(\.dismiss) var dismiss var isContinueButtonEnabled: Bool { !name.isEmpty && !email.isEmpty && CaseSensitivity.isValidEmail(email) && !username.isEmpty && CaseSensitivity.isValidUsername(username) && !password.isEmpty && CaseSensitivity.isValidPassword(password) && !phoneNumber.isEmpty && CaseSensitivity.isValidPhoneNumber(phoneNumber) } var body: some View { NavigationView { VStack { Image("uSTADIUM") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 191, height: 45) .padding(.top, -64) ZStack { VStack(alignment: .leading, spacing: 20) { HStack { Text("Personal Information") .font( Font.custom("Work Sans", size: 18) .weight(.bold) ) .foregroundColor(Color(red: 0.12, green: 0.12, blue: 0.12)) Spacer() Text("Step 1") .font(Font.custom("Work Sans", size: 14)) .fontWeight(.bold) .foregroundColor(Color(red: 0.1, green: 0.68, blue: 1)) } .padding(.horizontal, 24) TextFieldValidity(placeholder: "Enter your name", text: $name, isValid: true) TextFieldValidity(placeholder: "Enter your email", text: $email, isValid: CaseSensitivity.isValidEmail(email)) .autocapitalization(.none) TextFieldValidity(placeholder: "Enter your username", text: $username, isValid: CaseSensitivity.isValidUsername(username)) TextFieldValidity(placeholder: "Enter your password", text: $password, isValid: CaseSensitivity.isValidPassword(password)) TextFieldValidity(placeholder: "Enter phone number", text: $phoneNumber, isValid: CaseSensitivity.isValidPhoneNumber(phoneNumber)) NavigationLink(destination: PickYourInterestsView(signupState: signupState), isActive: $isNavigatingToInterests) { EmptyView() } Button(action: { if isContinueButtonEnabled { signUp() isNavigatingToInterests = true } }) { Text("Continue") .foregroundColor(.white) .font(Font.custom("Work Sans", size: 18)) .padding() .frame(maxWidth: .infinity) .background(isContinueButtonEnabled ? Color.blue : Color.gray) .cornerRadius(10) } .disabled(!isContinueButtonEnabled) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.top, 60) // Adjust the top padding as needed .padding(.horizontal) .padding(.bottom, 40) .background { Color.white .cornerRadius(16) .shadow(color: .black.opacity(0.08), radius: 20, x: 0, y: 6) .overlay( RoundedRectangle(cornerRadius: 16) .inset(by: 0.5) .stroke(Color(red: 0.88, green: 0.88, blue: 1), lineWidth: 1) ) } .padding() } } .navigationBarItems(leading: Button(action: { presentationMode.wrappedValue.dismiss() }, label: { Image(systemName: "arrow.backward.square.fill") .imageScale(.large) .font(.system(size: 24)) .foregroundColor(.gray) .padding(12) })) } } } extension SignUpView { func signUp() { let accountData = AccountSignup(email: email, username: username, password: password) AuthService.shared.signup(data: accountData) { result, error in if let error = error { print("Error: \(error.localizedDescription)") debugPrint(error) } else if result != nil { print("SignUp Successful!") } } } }
// // Signup.swift // uSTADIUM // // Created by Sonny Trujillo on 4/1/19. // Copyright © 2019 uSTADIUM. All rights reserved. // import Foundation import UIKit let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "Unkown" let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String ?? "Unkown" let systemVersion = UIDevice.current.systemVersion enum SignupType { case ustadium case facebook case twitter } struct ChangePassword: Encodable { var oldPassword: String? var newPassword: String } struct ForgotPassword: Encodable { var username: String var email: String } struct ForgotUsername: Encodable { var email: String } /// Response for the following apis. /// auth/valid/email/__ response structure /// auth/valid/username/__ response structure struct ValidResponse: Decodable { var message: String } /// api/users/refresh-firebasetoken response structure struct RefreshFirebaseResponse: Decodable { var firebaseToken: String } struct RegisterDevice: Encodable { var deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String var project = "abd87" var bundleID = "com.uSTADIUM.uSTADIUM1" var platform = "ios" var deviceName = UIDevice.current.name init(token: String){ self.deviceToken = token } } /// auth/reset-forgotten-password request structure struct ResetPasswordWithCode: Encodable { var code: String var password: String var username: String var deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String var project = "abd87" var bundleID = "com.uSTADIUM.uSTADIUM1" var platform = "ios" var deviceName = UIDevice.current.name init(code: String, username: String, password: String){ self.username = username self.password = password self.code = code } } /// auth/loginWithToken request structure. struct TokenReload: Encodable { var deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String var project = "abd87" var bundleID = "com.uSTADIUM.uSTADIUM1" var platform = "ios" var deviceName = UIDevice.current.name var referral: AccountReferral? } /// auth/token request structure. struct CustomAuth: Encodable { var username: String var password: String var feeds: [Int]? var deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String var project = "abd87" var bundleID = "com.uSTADIUM.uSTADIUM1" var platform = "ios" var deviceName = UIDevice.current.name var referral: AccountReferral? let appVersion = "ios(\(UIDevice.current.systemVersion)) \(UIDevice.current.modelName) uSTADIUM \(version)(\(build))" init(username: String, password: String, feeds: [Int]?){ self.username = username self.password = password self.feeds = feeds } } /// auth/facebook request structure struct FacebookAuth: Encodable { var access_token: String var deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String var feeds: [Int]? var project = "abd87" var bundleID = "com.uSTADIUM.uSTADIUM1" var platform = "ios" var deviceName = UIDevice.current.name var referral: AccountReferral? let appVersion = "ios(\(UIDevice.current.systemVersion)) \(UIDevice.current.modelName) uSTADIUM \(version)(\(build))" init(access: String, feeds: [Int]){ self.access_token = access self.feeds = feeds } } /// auth/twitter request structure struct TwitterAuth: Encodable { var oauth_token: String var oauth_token_secret: String var user_id: String var project = "abd87" var feeds: [Int]? var deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String var bundleID = "com.uSTADIUM.uSTADIUM1" var platform = "ios" var deviceName = UIDevice.current.name var referral: AccountReferral? let appVersion = "ios(\(UIDevice.current.systemVersion)) \(UIDevice.current.modelName) uSTADIUM \(version)(\(build))" init(oauth_token: String, oauth_secret: String, user_id: String, feeds: [Int]){ self.oauth_token = oauth_token self.oauth_token_secret = oauth_secret self.user_id = user_id self.feeds = feeds } } /// Account referral structure struct AccountReferral: Encodable { enum Result: String, Encodable { case registered case loggedIn } var link: URL let platform = "ios" var action: String var accountResult: AccountReferral.Result init(link: URL, action: String, accountResult: AccountReferral.Result){ self.link = link self.action = action self.accountResult = accountResult } } /// auth/signup request structure struct AccountSignup: Encodable { let email: String let username: String let password: String let project = "abd87" var feeds: [Int]? var keywords: [String]? var referral: AccountReferral? let platform = "ios" let deviceToken = UserDefaults.standard.object(forKey: "ustadiumDeviceToken") as? String let bundleID = "com.uSTADIUM.uSTADIUM1" let deviceName = UIDevice.current.name let appVersion = "ios(\(UIDevice.current.systemVersion)) \(UIDevice.current.modelName) uSTADIUM \(version)(\(build))" let deviceID = UIDevice.current.identifierForVendor?.uuidString ?? UserDefaults.getDeviceID() }
For AuthService
, the signup function is what's relevant as I call it in SignUpView and SignUp
has the definition for AccountSignUp
which is called in the other two files. What is not being read correctly in the data? What is missing and what can be done to fix it such that the info will be saved to the backend? All help will be greatly appreciated!