0

I'm new to Alamofire and now using Alamofire 5. I want to create a POST request with multipart form data, but there's a specific requirement for the JSON body. Here it is:

"item": [
    {
        "name": "Upload image",
        "request": {
            "method": "POST",
            "header": [],
            "body": {
                "mode": "formdata",
                "formdata": [
                    {
                        "key": "files[]",
                        "type": "file",
                        "src": []
                    },
                    {
                        "key": "mode",
                        "value": "public",
                        "type": "text"
                    }
                ]
            },
            "url": {
                "raw": "https://jsonplaceholder.typicode.com/api/image/upload",
                "protocol": "https",
                "host": [
                    "jsonplaceholder",
                    "typicode",
                    "com"
                ],
                "path": [
                    "api",
                    "image",
                    "upload"
                ]
            }
        },
        "response": []
    },
]

Anyone can help me how to post the data but with multipart form data? Please help. (It's okay if the POST request is using URLSession)

  • Why are you asking the same question as you already asked? https://stackoverflow.com/questions/70444111/alamofire-5-post-request-with-spesific-post-json-requirement can you please explain why you want this type of long request? – Shabnam Siddiqui Dec 23 '21 at 06:11
  • @ShabnamSiddiqui Because there are some changes with my question and I also don't know why it has to be that long request, it's just the requirement that I received. Can you help? – Gilbert Nicholas Dec 23 '21 at 06:18
  • Is that the whole JSON you are supposed to send, or is that the documentation of an API? Because that's different, since you'd just have to send the part `"formdata": [HERE]` which is quite basic, and I guess you've seen how to send multiform part data before hand, right? – Larme Dec 23 '21 at 06:28
  • @Larme And that's where I'm confused for. Yeah, I do think that is only documentation for the API and I intended to only send the "formdata" part. But I'm totally new with alamofire and post request, I also confused since in that documentation, "formdata" has 2 parts, which is the ["key", "type", "src"] and ["key", "value", "type"]. How to make multiple form data with that? – Gilbert Nicholas Dec 23 '21 at 06:51
  • https://stackoverflow.com/questions/55264097/upload-files-with-parameters-from-multipartformdata-using-alamofire-5-in-ios-swi/56320666 You "loop and append" twice. – Larme Dec 23 '21 at 06:54
  • @Larme Oh thank you! Yeah actually here's what makes me really confused. Am I supposed to send the whole JSON? Or only the "formdata" part? But how do you know that we are supposed to only send the "formdata" part and not the whole JSON? And are the remaining part like "name", "url" and other parts are generated automatically? – Gilbert Nicholas Dec 23 '21 at 07:00
  • It would be strange to do a request on an API and give again its own URL in the parameters. In my opinion, what you have is the description of the API, description that can be used for generating a "UI documentation", like Swagger etc. – Larme Dec 23 '21 at 07:15
  • @Larme Ahh, I see. Thank you very much for explaining all of these to me, really appreciate that! :D – Gilbert Nicholas Dec 23 '21 at 09:01

1 Answers1

1

Whatever I understand from your question and comments, I have created a method from your previous question.

func postImage(images: [UIImage],imgName : [String]) {
    var arrFormData = [[String:Any]]()
    var imgDataArray: [Data] = []

    for image in images {
        guard let imgData = image.jpegData(compressionQuality: 0.50) else { return }
        
        imgDataArray.append(imgData)
    }
    let param1: [String: Any] = [
            "key":"files[]",
            "type": "file",
            "src": imgName
        ]
    let param2: [String: Any] = [
        "key": "mode",
        "value": "public",
        "type": "text"
        ]
    var arrParam = [[String:Any]]()
    arrParam.append(param1)
    arrParam.append(param2)
    arrFormData.append(contentsOf: arrParam)
    var param : [String:Any] = [:]
    if let theJSONData = try? JSONSerialization.data(
        withJSONObject: arrFormData,
        options: []) {
        let theJSONText = String(data: theJSONData,
                                   encoding: .ascii)
        print("JSON string = \(theJSONText!)")
        param = ["formData" : theJSONText ?? ""]
    }
    print(param)
    Alamofire.upload(multipartFormData: {
        multipartFormData in
         for i in 0..<images.count{
            if let imageData = images[i].jpegData(compressionQuality: 0.6) {
                multipartFormData.append(imageData, withName: "file", fileName: "name.png", mimeType: "image/png")
            }
        }

        for (key, value) in param {
            multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
        }
    }, usingThreshold: 10 * 1024 * 1024,to: apiurl, method: .post, headers: headers, encodingCompletion: { encodingResult in
        switch encodingResult {
        case .success(let upload, _, _):
            upload.responseJSON {
                response in
                print(response.result)
            }
        case .failure(let encodingError):
            print(encodingError)
        }
    })
}
Shabnam Siddiqui
  • 579
  • 4
  • 13
  • Really thank you! But why I'm getting the Extra argument 'encodingCompletion' in call error? Is it supposed to not have the encodingCompletion? And what does the usingTreshold do? – Gilbert Nicholas Dec 23 '21 at 08:45
  • Might be you are using Alamofire 5, Alamofire 5 no longer requires an `encodingCompletion!` Instead, multipart form encoding is done as part of the standard now-asynchronous request process and will return errors on the `Request`, and they're available during `validate` and `response*` calls. – Shabnam Siddiqui Dec 23 '21 at 09:18
  • For Alamofire 5 take a look here https://stackoverflow.com/questions/54985001/alamofire-5-upload-encodingcompletion – Shabnam Siddiqui Dec 23 '21 at 09:20
  • Ahh okay, and when you try to access image[0], did you mean you want to access images[0]? Because there's no image variable in there to be accessed – Gilbert Nicholas Dec 23 '21 at 10:51
  • I have edited my answer. hope it will clear all your doubts. – Shabnam Siddiqui Dec 23 '21 at 10:57
  • Just one more and last thing, sorry to bother you very much. When the code running multipartFormData.append((value as AnyObject).data(.....)), the app crashes, saying unrecognized selector sent to instance. I just wondering maybe the value as any object is not compatible with the encoding? Thank you and once again sorry to bother you very much – Gilbert Nicholas Dec 23 '21 at 11:30
  • No, it's ok. can you please send your code to me? so I can test it and let you trouble out or you can share only the API link I'll go through it and inform you ASAP. – Shabnam Siddiqui Dec 23 '21 at 11:38
  • It's very kind of you. Here's link to the project: https://github.com/GilbertNicholas/test.git really appreciate your help – Gilbert Nicholas Dec 23 '21 at 12:01
  • Now the API gives response but it is like `DEBUG: The files field is required.` please handle it with your end and you just need to add the proper `withName` in `multipartFormData.append(imageData, withName: "file", fileName: "name.png", mimeType: "image/png")` – Shabnam Siddiqui Dec 23 '21 at 12:33
  • How about the crash that I mentioned before? How do you make it work? Because I still have that error. And yeah, actually I've tried many times with different methods but the API gives a response just like you get. Maybe you can try with this API https://jsonplaceholder.typicode.com/posts – Gilbert Nicholas Dec 23 '21 at 12:39
  • the crash issue is solved now, just looked at the answer. And above-mentioned API gives response but not in `Alamofire.upload`. for that you have to create a another API Call with get/post method. – Shabnam Siddiqui Dec 23 '21 at 12:42
  • Ooh, so with the jsonplaceholder.typicode API, we won't get any response from the Alamofire upload? – Gilbert Nicholas Dec 23 '21 at 12:58