AFNetworking posts JSON arrays as multiple single-entry dictionaries
Asked Answered
L

4

5

I'm having a similar issue to the one discussed here.

I'm attempting to post JSON to a server.

Here's the Objective-C code that should work, but doesn't. I get an empty array in the response object, not sure why:

    AFHTTPRequestOperation * operation = [manager POST:uploadScriptUrl
      parameters:mutableJSON
      success:^(AFHTTPRequestOperation * operation, id responseObject) {
          successBlock(operation, responseObject);
      }
      failure:^(AFHTTPRequestOperation * operation, NSError * error) {
          failureBlock(operation, error);
      }];

This code (which is adapted from code I use to upload images) KIND OF works. I know it's definitely not the approved way to do it:

    AFHTTPRequestOperationManager * manager = [AFHTTPRequestOperationManager manager];
    AFJSONRequestSerializer * requestSerializer = [AFJSONRequestSerializer serializer];
    [requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    manager.requestSerializer = requestSerializer;

    AFHTTPRequestOperation * operation = [manager POST:uploadScriptUrl
    parameters:mutableJSON //passed in
    constructingBodyWithBlock:^(id <AFMultipartFormData> formData) {
        //Do nothing
   }
    success:^(AFHTTPRequestOperation * operation, id responseObject) {
        successBlock(operation, responseObject);
    }
    failure:^(AFHTTPRequestOperation * operation, NSError * error) {
        failureBlock(operation, error);
    }];

It posts my JSON to the server, but in the process of formulating the request, the JSON is mangled.

Here's how it starts out:

{
"key1": [
    {
        "dictionary1": {
            "param1": "value1",
            "param2": "value2",
            "array1A": [
                "value1",
                "value2"
            ],
            "array1B": [
                "value1",
                "value2"
            ]
        }
    }
]

}

and here's what AFNetworking sends to the server:

{
"key1": [
    {
        "dictionary1": {
            "array1A": [
                "value1"
            ]
        }
    },
    {
        "dictionary1": {
            "array1A": [
                "value2"
            ]
        }
    },
    {
        "dictionary1": {
            "array1B": [
                "value1"
            ]
        }
    },
    {
        "dictionary1": {
            "array1B": [
                "value2"
            ]
        }
    },
    {
        "dictionary1": {
            "param1": "value1"
        }
    },
    {
        "dictionary1": {
            "param2": "value2"
        }
    }
]

}

Here's what Charles shows for the request. You can see how the JSON structure has already been altered in the request, before the server has touched the data.

Here's the PHP I'm using on the server. Dead simple for now:

<?php

header('Content-type: application/json'); //Not sure if this is needed.

$json_string = json_encode($_POST);

header("HTTP/1.0 200 OK");
echo $json_string;

?>

So, all of that said, here are my questions:

  1. Does AFNetworking handle nested JSON arrays? On this page Mattt says: "The structure you're describing can't deterministically be represented with query string encoding." I'm using POST, so query strings are not involved. But maybe the limitation exists with POST data as well?

  2. I'm also curious why the longer AFNetworking call that includes constructingBodyWithBlock succeeds while the shorter one fails. However, this answer is less important to me. The longer method very nearly works and I'd be happy to use it if it returned the same JSON that I send.

Thanks all!

Lello answered 24/1, 2014 at 23:51 Comment(0)
L
7

I'm using POST, so query strings are not involved. But maybe the limitation exists with POST data as well?

The limitation is not on POST, it's URL form encoding. I go on to say that you should encode as JSON, which you can do with the following configuration change to your manager:

manager.requestSerializer = [AFJSONRequestSerializer serializer];.

Also, unless you're actually constructing a multi-part request, don't use the constructingBodyWithBlock version of that method.

Lumbago answered 27/1, 2014 at 23:15 Comment(1)
I had done that, but didn't include it in post. Should have, but post seemed awfully long. I've edited the original post to include it. Thanks for clarifying the limitations and where they come from. So, how would I go about uploading JSON of whatever complexity I choose?Lello
L
4

I just dealt with the same issue and the only solution I could find was to create a dictionary out of the array. There must be a better way, this is pretty ugly...

    NSMutableDictionary *arrayDict = [[NSMutableDictionary alloc] init];
    int counter = 0;
    for (NSMutableDictionary *arrayItem in arrayToSend) {
        [arrayDict setObject:arrayItem forKey:[NSNumber numberWithInt:counter]];
        counter++;
    }

Otherwise everything got flattened sort of. I use AFJSONRequestSerializer, but that doesn't seem to matter.

Lukelukens answered 5/4, 2014 at 1:9 Comment(1)
This is the simplest way for getting the encoding when the data has to be sent in the url queryWoodsum
A
0

Ugly solutions are for the weak minded: How can I POST an NSArray of NSDictionaries inside an NSDictionary without problems?

The answer to this post contains all you need.

Arvie answered 24/5, 2015 at 12:58 Comment(0)
P
0

I too had this issue recently, I had the following parameters to be sent to the server, but the "feature" array was breaking into 4 parts rather than just 2 dictionaries.

        { "description": "Temporary Description",   
          "name": "Product Name",  
          "feature": [
            {
              "fkey": "FT1",
              "fvalue": "FD1"
            },
            {
              "fkey": "FT2",
              "fvalue": "FD2"
            }   
         ] 
    }

So I changed the

AFURLRequestSerialisation.m

replaced this line in AFQueryStringPairsFromKeyAndValue(NSString *key, id value) method

[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];

with

[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[%i]", key, [array indexOfObject:nestedValue]], nestedValue)];

And this did the trick. I hope this might help someone.

Palmitate answered 10/4, 2016 at 19:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.