Search code examples
iosswiftalamofire

Alamofire 5: Upload Failed: Response could not be decoded because of error: The data couldn’t be read because it is missing


As the title says, Alamofire 5 is telling me that the data is missing, yet it is not.

This is the data I have in my console along with the error

dic=== {"lat": "26.9342246", "message": "Test", "lng": "-80.0942087", "receiver_id": "269", "messageType": "text", "chatType": "fix", "product_variant_id": "", "receiverType": "customer", "customer_id": "213", "itemType": "sell", "product_id": "25", "service_id": "", "fileName": ""}
Result: failure(Alamofire.AFError.responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "message", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"message\", intValue: nil) (\"message\").", underlyingError: nil)))))
Upload Failed: Response could not be decoded because of error:
The data couldn’t be read because it is missing.

These are my Decodable's

struct MessageModel : Decodable {
                let data : [MessageModelData]?
                let message : String
                
                enum CodingKeys: String, CodingKey {
                        case message, data
                    }
            }

            struct  MessageModelData : Decodable {
                let fileType : String
                let groupID, id : Int
                let intetestCustomerID, itemType, message, messageType : String
                let productID, productOwnerID, profileImg, profileName :String
                let receiveID, receiverType, sendAt : String
                
                enum CodingKeys: String, CodingKey {
                        case groupID = "groupId"
                        case intetestCustomerID = "intetest_customer_id"
                        case productID = "product_id"
                        case productOwnerID  = "product_owner_id"
                        case receiveID = "receiveId"
                        case fileType, id, itemType, message, messageType, profileImg, profileName, receiverType, sendAt
                    
                    }
                
            }

Am I missing something? I changed message to an optional and then it said unexpectedly found nil, I'm very confused as clearly the message variable is in the response.

Here's where it errors

func sendChatProductImage(header: String, parameter: String, coverdata: UIImage, mimetype : String ,vc: UIViewController, showHud: Bool,completion : @escaping(_ success : Bool, _ message : String, _ response : NSDictionary) -> Void) {
        webService_obj.chatProductImageSend(header: header, withParameter: parameter, coverdata: coverdata, mimetypeExtention: mimetype, inVC: vc, showHud: showHud) { (response, success) in
            if success{
                let message = response["message"]
                completion(success, message as! String, response )
            }
        }
    }

EDIT:

I figured out why, but I don't know how to resolve it.

I have my upload here with Alamofire 5, and I have the decodable, but it is not properly decoding it to the right data, or I'm using the response wrong

AF.upload(
                multipartFormData: { multipartFormData in
                    var dic = parameter.replacingOccurrences(of: "[", with: "{")
                    dic = dic.replacingOccurrences(of: "]", with: "}")
                    print("dic===",dic)
                    multipartFormData.append("\(dic)".data(using: String.Encoding.utf8)!, withName: "data")
                    if coverimageData != nil {
                        multipartFormData.append(coverimageData!, withName: "file", fileName: "chatImage.jpg", mimeType: "*/*")
                    }else{
                        multipartFormData.append("".data(using: String.Encoding.utf8)!, withName: "file")
                    }
                    
            },
                with: uploadUrl).responseDecodable(of: MessageModel.self) { response in
                    print("Result: \(response)")
                    
                    if hud {
                        Loader.init().hide(delegate: vc)
                    }
                    switch response.result {
                    case .success(let result):
                        let dataResponse = response.value(forKey: "data" as? NSDictionary)
                        completion(dataResponse, true)
                    case .failure(let error):
                        let err = error.localizedDescription
                        print("Upload Failed: \(err)")
                        completion([:], false)
                        self.presentAlertWithTitle(title: kAPPName, message: err, vc: vc)
                        break
                    }
                }

Solution

  • As you can see your MessageModel struct does not match the json data you get from the server in response to yourupload. In particular there is no response property. Similarly for MessageDataType.

    Try the following models, to decode the response you get from the server after you have sent your data to it:

    struct PostResponse: Codable {
        let response: MessageDataType    <-- here
    }
    
    struct MessageDataType: Codable {
        let status_code: Int
        let message, data: String
    }
    

    and decode the response like this:

     //...
        with: uploadUrl).responseDecodable(of: PostResponse.self) { <-- here
     //....
    

    You will have to read the server docs to determine which of the properties should be optional, in that case add ? to it.

    EDIT-1

    To decode the response you are now showing, instead of the one you showed us before,

    Optional("{\"response\":{\"status_code\":200,\"message\":\"Message sent successfully.\",\"data\":\"154\"}}")

    use the following models:

    struct PostResponse: Codable {
        let response: StatusResponse
    }
    
    struct StatusResponse: Codable {
        let status_code: Int
        let message: String
        let data: DataClass
    }
    
    struct DataClass: Codable {
        let chatId, senderId, receiveId, senderType: String
        let message, lat, lng, file: String
        let fileName, fileType, messageType: String
    }