1

Below is my code referring this question answer

func createRequest(ResumeID: String, CandidateID: String, MediaName: String, FileExtension : String, MediaType : String) throws -> URLRequest {

    let parameters = NSDictionary(objects: [ResumeID, CandidateID, MediaName, FileExtension,MediaType], forKeys: ["ResumeID" as NSCopying, "CandidateID" as NSCopying, "MediaName" as NSCopying, "FileExtension" as NSCopying, "MediaType" as NSCopying])

    let boundary = generateBoundaryString()

    let url = URL(string: "http://192.168.1.29/ColorsKit_New_Svr/WTCSvr.svc/WTCService?Id=6&SPName=Usp_RTN_IU_CandidateSubmissionResume")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

    let path1 = Bundle.main.path(forResource: "dummy-pdf_2", ofType: "pdf")!
    request.httpBody = try createBody(with: parameters as? [String : String], filePathKey: "MediaContent", paths: [path1], boundary: boundary)

    return request
}

private func createBody(with parameters: [String: String]?, filePathKey: String, paths: [String], boundary: String) throws -> Data {
    var body = Data()

    if parameters != nil {
        for (key, value) in parameters! {
            body.append("--\(boundary)\r\n")
            body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.append("\(value)\r\n")
        }
    }

    for path in paths {
        let url = URL(fileURLWithPath: path)
        let filename = url.lastPathComponent
        let data = try Data(contentsOf: url)
        let mimetype = mimeType(for: path)

        body.append("--\(boundary)\r\n")
        body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename)\"\r\n")
        body.append("Content-Type: \(mimetype)\r\n\r\n")
        body.append(data)
        body.append("\r\n")
    }

    body.append("--\(boundary)--\r\n")
    return body
}

func sendMultipartRequest() {
    let request: URLRequest

    do {
        request = try createRequest(ResumeID: "1", CandidateID: "1241124", MediaName: "dummy-pdf", FileExtension: "pdf", MediaType: "pdf")
    } catch {
        print(error)
        return
    }

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard error == nil else {
            // handle error here
            print(error!)
            return
        }

        // if response was JSON, then parse it

        do {                
            let responseDictionary = try JSONSerialization.jsonObject(with: data!)
            print("success == \(responseDictionary)")

            // note, if you want to update the UI, make sure to dispatch that to the main queue, e.g.:
            //
            // DispatchQueue.main.async {
            //     // update your UI and model objects here
            // }
        } catch {
            print(error)

            let responseString = String(data: data!, encoding: .utf8)
            print("responseString = \(String(describing: responseString))")
        }
    }
    task.resume()
}

The Response I'm getting is:

Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.} responseString = Optional("No Records Found")

This is strange because Postman is giving correct response. Means there is something missing in the code only :(

enter image description here

Krutika Sonawala
  • 1,065
  • 1
  • 12
  • 30
  • check once in your backend , its a valid JSON – Anbu.Karthik Jan 12 '18 at 06:41
  • This should be valid as I'm getting a perfect response via "Postman" – Krutika Sonawala Jan 12 '18 at 06:41
  • post Man gives correct answer, by our coding level it occur error, – Anbu.Karthik Jan 12 '18 at 06:44
  • yes, that only i'm saying – Krutika Sonawala Jan 12 '18 at 06:46
  • As an aside, your question title and tags say Alamofire, but you're building it manually (which is more work than Alamofire). Do you want to use Alamofire or not? – Rob Jan 12 '18 at 06:50
  • On the server side add header('Content-type: application/json'); in .php code. – Dixit Akabari Jan 12 '18 at 06:50
  • are you using almorafire? – Dixit Akabari Jan 12 '18 at 06:51
  • You logged `responseString`: `responseString = Optional("No Records Found")`. That means that your server did not return JSON, but rather it returned a string literal, "No Records Found". I'd suggest you go back to the web service and figure out in what situation it would report "No Records Found". – Rob Jan 12 '18 at 06:52
  • @Rob I'm very new to Alamofire. I seriously don't know the difference between alamofire code and my code. And postman is not giving "No records found" for the same parameters and values. It is giving success message. – Krutika Sonawala Jan 12 '18 at 07:00
  • Alamofire just makes it a _lot_ easier to create multipart requests. But I would wager that Alamofire multipart request would return the same error. Personally, I'd watch this in [Charles](http://charlesproxy.com) or [WireShark](http://wireshark.org) and then watch the postman rendition and compare. There's likely some subtle difference that is eluding us: E.g., your postman said "ResumeID" was "0", but your Swift code is sending "1". Is that deliberate? Your Swift rendition is including a bunch of parameters in the URL. Did you do that in postman rendition? – Rob Jan 12 '18 at 07:06
  • @Rob ok.. can you identify the mistake in the above code? if any. Or this should work perfectly? – Krutika Sonawala Jan 12 '18 at 07:13
  • I don't see any obvious request, but clearly if postman is working and this isn't, there's some difference which is eluding us. We can't diagnose the problem on the basis of the information provided. Have you looked at the web service and figured out what triggers the "No Records Found" error? – Rob Jan 12 '18 at 07:15
  • And, again, why did you set "ResumeID" to "1" instead of "0"? I wonder if a non-zero `ResumeID` means that it's looking for that particular resume and is reporting (unproductively) that it couldn't find a `ResumeID` of 1. It's a random guess, but it's the only obvious difference that I see here. The server code is apparently looking for something and isn't finding a record, and that's the only thing that is jumping out at me. – Rob Jan 12 '18 at 07:26
  • This answer is helpful for for you https://stackoverflow.com/a/47952330/6822622 – AshvinGudaliya Jan 12 '18 at 07:28
  • And also check this answer = https://stackoverflow.com/q/47863532/6822622 – AshvinGudaliya Jan 12 '18 at 07:34
  • @Rob There is no difference in response replacing 1 with 0 on ResumeID. I have asked web team to verify if they are sure that service and response both are JSON. They said Yes. – Krutika Sonawala Jan 12 '18 at 08:29
  • You should just ask them in what case the web service could ever return "No Records Found" rather than returning a valid JSON response. I'm not sure why we should be guessing... – Rob Jan 12 '18 at 09:17

2 Answers2

1

Use Alamofire

let upload_url = "your url"
let fieldName = "UploadedFile"
let mimeType = "plain/text"


Alamofire.upload(multipartFormData: { multipartFormData in

//you can add multiple file
        multipartFormData.append(fileData as Data, withName: fieldName, fileName: fileName, mimeType: mimeType)

    }, to: upload_url, method: .post, headers: ["Authorization": "auth_token"],

       encodingCompletion: { encodingResult in
        switch encodingResult {
        case .success(let upload, _, _):
            upload.response { [weak self] response in
                guard let _ = self else {
                    return
                }
                debugPrint(response)
            }
        case .failure(let encodingError):
            debugPrint("uploaderService error:\(encodingError)")
        }

    })
Supran Jowti
  • 371
  • 2
  • 9
0

Use JSONSerialization as below

if let responseDictionary = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String {

...
}
pkc456
  • 8,350
  • 38
  • 53
  • 109