Search code examples
iosswiftfile-uploadmultipartform-datadocument

Server response throwing Unable to process while uploading document/Photo to server in Swift


I am trying to uploading document to server. In Action sheet, User can choose Photo from gallery to Document to upload.

So, I am taking either photo or document and converting it into Data. After that I am sending that data to server along with two parameters (keys, values) with multipart.

But, Unfortunately I am getting error like Unable to process from server, But same thing working in Android domain.

Here is my code:

    func uploadDocument(documentId:Int, data: Data, filePath: String, categoryType: String, completion: @escaping uploadDocumentClosure) {
        
        let url = "https://somedomain.com/uploadDocument"
        
        let requestURL = URL(string: url)!
        let request = NSMutableURLRequest(url: requestURL)
        request.cachePolicy = .reloadIgnoringLocalCacheData
        request.httpShouldHandleCookies = false
        request.timeoutInterval = 30
        request.httpMethod = "POST"

        let filename = "avatar.png"
        // generate boundary string using a unique per-app string
        let boundary = UUID().uuidString

        let docData = data
        
             let idStr = "id"
            let docTypeStr = "documentType"
            let file = "file"
        
        var data = Data()

        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        request.addValue("Bearer \(accessToken ?? "")", forHTTPHeaderField: "Authorization")
        request.httpMethod = "POST"
        
        data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)

        data.append("Content-Disposition: form-data; name=\"\(docTypeStr)\"\r\n\r\n".data(using: .utf8)!)
        data.append("\(categoryType)".data(using: .utf8)!)

        data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
        data.append("Content-Disposition: form-data; name=\"\(file)\"\r\n\r\n".data(using: .utf8)!)

        // Add the image data to the raw http request data
        data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
//        data.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
//
        if let dataa = "Content-Disposition: form-data; name=\"\(filename)\"; filename=\"image.jpg\"\r\n".data(using: .utf8) {
            data.append(dataa)
        }

        data.append("Content-Type: image/png\r\n\r\n".data(using: .utf8)!)
        data.append(docData)

        data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
        
        self.serviceManager.async(request: request as URLRequest) { (innerClosure) in
            do {
                let response = try innerClosure()
                guard let json = response.jsonObject else {
                    completion({ throw JSONErrorType.parsingError })
                    return
                }
                let jsonData = try JSONSerialization.data(withJSONObject: json, options: [])
                let responseModel = try JSONDecoder().decode(EditProfilePhotoUploadResponse.self, from: jsonData)
                completion({ return responseModel })
            } catch {
                completion({ throw error })
            }
        }
    }

And the sever response is below

{
  "status" : "E",
  "message" : "Unable to process.",
  "data" : null,
  "messageList" : null
}

With status code 400 bad request. In Android they simply sending below code and its working fine.

@Multipart
@POST("somedomain.com/uploadDocument")
suspend fun uploadDocument(
    @Part file: MultipartBody.Part,
    @Query("documentType") documentType: String
): GenericMessageResponse

Any suggestions?


Solution

  • After much debugging, I have fixed the issue with below solution.

    I used below library

    https://github.com/Fyrts/Multipart.git
    

    Here my code changes are below

        func uploadDocument(imageData: Data, filePath: String, fileName: String, categoryType: String, completion: @escaping uploadDocumentClosure) {
            
            let url = "https://wwww.somedomain.com/uploadDocument"
            let requestURL = URL(string: url)!
                        
            let imageeData = ImageData(name: fileName, filePath: filePath, imagedata: imageData)
            
            let string = imageeData.filePath
            
            let mimeType = string.mimeType() //here list of mimes we can get from predefined
            
            let fileContents = try! Data(contentsOf: URL(string: filePath)!)
            
            var message = Multipart(type: .formData)
            message.append(Part.FormData(name: "documentType", value: "\(categoryType)"))
            message.append(Part.FormData(name: "file", fileData: fileContents, fileName: "\(imageeData.name)", contentType: "\(mimeType)"))
            
            var URLrequest = URLRequest(url: requestURL)
            URLrequest.httpMethod = "POST"
            URLrequest.setMultipartBody(message)
            URLrequest.addValue("/(token)", forHTTPHeaderField: "Authorization")
            
            self.serviceManager.async(request: URLrequest as URLRequest) { (innerClosure) in
                do {
                    let response = try innerClosure()
                    guard let json = response.jsonObject else {
                        completion({ throw JSONErrorType.parsingError })
                        return
                    }
                    let jsonData = try JSONSerialization.data(withJSONObject: json, options: [])
                    let responseModel = try JSONDecoder().decode(EditProfilePhotoUploadResponse.self, from: jsonData)
                    completion({ return responseModel })
                } catch {
                    completion({ throw error })
                }
            }
        }