6

I have an array of dictionaries that I am trying to post to Alamofire with the help of SwiftyJSON.

The api is set to take:

[
    {
        "imageUrl": "someimage3.jpg"
    },
    {
        "imageUrl": "someimage4.jpg"
    }
]

My array with image objects when printed out looks like this with the imageUrl key and image name for the value.

uploadedFiles = [
    [imageUrl: "someimage.jpg"],
    [imageUrl: "someimage2.jpg"]
]

I'm trying to convert the array of dictionaries into the format needed for the body. I'm not quite sure how to get them to be [String: AnyObject]

var body: [String: AnyObject] = [:]
let paramsJSON = JSON(uploadedFiles)
body = paramsJSON

alamofire post

Alamofire.request("\(BASE_URL)mainimages/\(someid)", method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseString { (response) in
        if response.result.error == nil {
            let status = response.response?.statusCode
            completion(true, status)
        } else {
            completion(false, nil)
            debugPrint(response.result.error as Any)
        }
    }
Keith
  • 1,969
  • 4
  • 17
  • 27

4 Answers4

3

You can done this by constructing manual request and call the Alamofire.request as below

var request = URLRequest(url: .......))
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")

//parameter array

let uploadedFiles = [
   [imageUrl: "someimage.jpg"],
   [imageUrl: "someimage2.jpg"]
]

request.httpBody = try! JSONSerialization.data(withJSONObject: uploadedFiles)

Alamofire.request(request).responseJSON { response in

    switch (response.result) {
    case .success:

        //success code here

    case .failure(let error):

        //failure code here
    }
}

If you can easily change the format in Sever side, ignore the above solution and changed as dictionary

[ "list_key" : [
       [imageUrl: "someimage.jpg"],
       [imageUrl: "someimage2.jpg"]
    ] 
 ]
Mani
  • 17,549
  • 13
  • 79
  • 100
  • Mani, you probably made a typo: your suggested JSON is still an array respectively not valid JSON ;) – CouchDeveloper Apr 26 '18 at 07:24
  • @CouchDeveloper Yes. I know. But I'm not setting `Alamofire's params`, instead i'm directly setting `httpbody`. whose said, Array of Dictinoary is not valid JSON? – Mani Apr 26 '18 at 07:26
  • Well, your JSON is not exactly valid - it's just not a dictionary as you stated. It's a JSON Array of JSON Objects (Dictionaries). If you want to post some kind of object as JSON, it's best to use a JSON Object (aka Dictionary) as the root. If you want to post an array of some kind of objects, you can post an JSON Array of JSON Objects (as this kind of object) to the server. I think we agree :) – CouchDeveloper 5 mins ago edit – CouchDeveloper Apr 26 '18 at 08:19
  • @CouchDeveloper You can use the Foundation framework’s J`SONSerialization` class to convert JSON into Swift data types like `Dictionary, Array, String, Number, and Bool`.. see here https://developer.apple.com/swift/blog/?id=37 so the object don't need to be a dictionary for converting it into JSON, it may be any one of mentioned types. – Mani Apr 26 '18 at 08:47
  • one more point. Ya this is right `it's best to use a JSON Object (aka Dictionary) as the root`, But at the same time, if root object is not Dictionary, we can't say that's not JSON. It's also JSON. – Mani Apr 26 '18 at 09:10
  • I get this error *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (_SwiftValue)' – Keith Apr 27 '18 at 00:13
  • I also tried reformatted my api like your second suggestion. Api is fine but when passing in the body I get the same invalid JSON error. let body: [String: AnyObject] = [ "allImages": uploadedFiles as AnyObject ] – Keith Apr 27 '18 at 02:59
3

You can achieve using this method, It worked for me.

let payload = [["eventName": "Notifications","body":["version": "1.0","latitude": lat,"longitude":lon]]] as [[String : AnyObject]]

trackEventRequest(requestParams: payload, urlString: "https://xyz/youyURL")





func trackEventRequest(requestParams: [[String: AnyObject]], urlString: String) {

        let url = URL(string: urlString)
        var request = URLRequest(url: url!)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        request.httpBody = try! JSONSerialization.data(withJSONObject: requestParams, options: [])

        Alamofire.request(reqeust).responseJSON { (response) in
            switch response.result {
            case .success:
                print(response.result.value)
                break
            case .failure:
                print(response.error)
                break
            }
        }
    }
Purnendu roy
  • 818
  • 8
  • 15
1

The API seems to take a JSON that has an array as the top level, not a dictionary, so converting your array to a dictionary is incorrect.

Just pass an array in!

SwiftyJSON's JSON conforms to ExpressibleByArrayLiteral, so you can just use an array literal:

let paramsJSON: JSON = [
    ["imageUrl": "someimage.jpg"],
    ["imageUrl": "someimage2.jpg"]
]

EDIT: I just realised that Alamofire's request method only accepts a [String: AnyObject]. This means that you need to do your own parameter encoding, demonstrated here.

Alternatively, create your own URLRequest, as shown in this post:

var request = URLRequest(url: someURL)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = paramsJSON.rawData()
Alamofire.request(request)
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Sorry I may have not been clear, I'm not trying to convert it to a dictionary, that is what I have now. Just get it into something I can pass to alamofire. I tried your array and get the error "Extra argument 'method' in call" – Keith Apr 26 '18 at 06:13
  • This does solve the problem of not being able to upload my array with Alamofire. I'm still having an issue getting my array of dictionaries into the correct JSON format. let paramsJSON: JSON = JSON(uploadedFiles) gives me unknown. uploadedFiles printed out looks like this: [MyApp.NoteImage(imageUrl: "https://someimage.png”), MyApp.NoteImage(imageUrl: "https://someimage2.png")] – Keith Apr 26 '18 at 23:45
0

I reformatted my API like Mani suggested to make it easier to give Alamofire what is needed. It's now looking for this:

{
    "allImages" : [
        {
            "imageUrl": "someimage5.jpg"
        },
        {
            "imageUrl": "someimage6.jpg"
        }
    ]
}

I also had to reformat my array like the code below to get the JSON errors to go away.

var newUploadFilesArray = [AnyObject]()
    for item in uploadedFiles {
        let singleImageDict = ["imageUrl" : item.imageUrl]
        newUploadFilesArray.append(singleImageDict as AnyObject)
    }

    let body: [String: AnyObject] = [
        "allImages": newUploadFilesArray as AnyObject
    ]

    Alamofire.request("\(BASE_URL)mainimages/\(mainId)", method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseString { (response) in
        if response.result.error == nil {
            let status = response.response?.statusCode
            completion(true, status)
        } else {
            completion(false, nil)
            debugPrint(response.result.error as Any)
        }
    }
Keith
  • 1,969
  • 4
  • 17
  • 27