How can I POST an NSArray of NSDictionaries inside an NSDictionary without problems?
Asked Answered
C

3

4

I do know how to do this, it's fairly simple.

The problem is that it doesn't work.

Here's the function I use to POST the data:

- (void)updateWebsitesUsingParameters:(NSDictionary *)parameters;
{
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

    [manager POST:@"http://notreal/updateWebsites.php"
       parameters:parameters
          success:^(AFHTTPRequestOperation *operation, id responseObject) {

              NSLog(@"JSON: %@", responseObject);

              //...
          }
          failure:^(AFHTTPRequestOperation *operation, NSError *error) {

              //...
          }];
}

Here are the parameters:

NSDictionary *parameters = @{@"type" : @"0",
                             @"credentials" : @{@"email" : @"[email protected]", @"password" : @"notreal"},
                             @"device" : @{@"ID" : @"8588107756600540", @"numberOfSessions" : @"0", @"name" : @"Nick's iMac"},
                             @"websites" : @[@{@"title" : @"Google", @"URL" : @"http://www.google.com"}, @{@"title" : @"Yahoo", @"URL" : @"http://www.yahoo.com"}]};

Here's what gets saved in the MySQL field:

[{URL = "http://www.google.com";},{title = Google;},{URL = "http://www.yahoo.com";},{title = Yahoo;}]

THIS IS CRAZY!

  1. I have successfully saved JSON of an array of dictionaries with multiple attributes inside a dictionary inside a MySQL field --or in short what I'm trying to do here-- using a PHP script for a different purpose and it works, no problem.
  2. I use the same PHP code to save it to the MySQL field so IT'S NOT PHP'S FAULT.
  3. All other save / retrieve functions I have made using AFNetworking work perfectly.

This works:

@[@{@"title" : @"Google"}, @{@"title" : @"Yahoo"}]

This doesn't:

@[@{@"title" : @"Google", @"URL" : @"http://www.google.com"}, @{@"title" : @"Yahoo", @"URL" : @"http://www.yahoo.com"}]

Here's the response:

{
    websites =     (
                {
            URL = "http://www.google.com";
        },
                {
            title = Google;
        },
                {
            URL = "http://www.yahoo.com";
        },
                {
            title = Yahoo;
        }
    );
}

INSANE!

For some reason, it breaks down if I add an extra attribute.

This must be an AFNetworking bug because it makes no sense.

EDIT:

I could:

  1. Make two MySQL fields: websiteTitles, websiteURLs.

  2. Save it as one string: "Google;http://www.google.com" and then separate it but that defeats the purpose of using JSON.

  3. Send the parameters chopped in half: websteTitles, websiteURLs

All are hideous, any ideas?

EDIT 2:

I run a few tests:

It doesn't matter if the array has 1 or 2 items it still behaves like this.

I tried what rob180 suggested and --as expected-- it's AFNetwokring's fault:

{
    websites =     (
                {
            URL = "http://www.google.com";
        },
                {
            title = Google;
        },
                {
            URL = "http://www.yahoo.com";
        },
                {
            title = Yahoo;
        }
    );
}

This is the actual server response of what has been send from the app, no mysql in the middle.

EDIT 3:

REQUEST: <NSMutableURLRequest: 0x7f9352d467e0> { URL: http://notreal/updateWebsites.php }

The HTTPBody looks like this:

<63726564 656e7469 616c735b ... 653d30>

How can I decode this?

Also, I'm using an AFHTTPRequestSerializer. Maybe, if I change it to AFJSONRequestSerializer it will fix the problem but I really don't want to since I have written many methods this way.

Chrotoem answered 21/5, 2015 at 21:25 Comment(7)
try sending the parameters that you send to the server as a response. That way you can see if the problem is on iOS or or PHP.Mg
have you tried to set requestSerializer?Spout
No, I didn't need to set the requestSerializer for more than 10 methods. Now, perhaps I need it but how? What setting will fix this?Chrotoem
what do you mean when you say that it does not work? Have you tried to log the request on the server side to see what you are getting or are you getting nothing?Grandstand
Can you print out your requests body on the iOS side and add it to your question? The request should be in the operation ( operation.request )Worden
How can I decode the request body?Chrotoem
Any ideas? I'm stuck here...Chrotoem
C
3

"query string parameterization is simply not a reliable way of encoding nested data structures. This is why all modern web frameworks have built-in conveniences that automatically decode incoming JSON into parameters." - Mattt Thompson

So, JSON it is...

Parameters:

NSDictionary *parameters = @{@"websites" : @[@{@"Title" : @"Google", @"URL" : @"http://www.google.com"}, @{@"Title" : @"Yahoo", @"URL" : @"http://www.yahoo.com"}]};

Send:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];

    [manager POST:@"http://server/path/file.php"
       parameters:parameters
          success:^(NSURLSessionDataTask *task, id responseObject) {

              NSLog(@"JSON: %@", responseObject);
          }
          failure:^(NSURLSessionDataTask *task, NSError *error) {

              NSLog(@"Error: %@", error.description);
          }];

Retrieve:

<?php

header('Content-type: application/json');

$request = json_decode(file_get_contents('php://input'), TRUE);

$response = ["URLOfTheSecondWebsite" => $request['websites'][1]['URL']];

echo json_encode($response);

?>

Response:

{
    URL = "http://yahoo.com";
}

All done!

Pure gold.

Chrotoem answered 23/5, 2015 at 11:48 Comment(2)
This answer should be pinned on the homepage. It reliefs newbies like me of all frustration so easily... :')Chrotoem
Justice will be served. The truth will outshine the sparkling world of sciolism my fellow overflower.Chrotoem
K
2

update function AFQueryStringPairsFromKeyAndValue

change

     for (id nestedValue in array) {
         [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
     }

to

     int i = 0;
     for (id nestedValue in array) {
         [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[%d]", key, i++], nestedValue)];
     }
Kimes answered 28/6, 2016 at 6:33 Comment(0)
B
0

Had the same issue with AFHTTPSessionManager. Unfortunately you have to switch to AFJSONRequestSerializer to send array of dictionaries:

manager.requestSerializer = [AFJSONRequestSerializer serializer];

AFJSONRequestSerializer sets application/json content-type and server that expects JSON will successfully accept request parameters while AFHTTPRequestSerializer will always have text/html content-type in header even if you set it explicitly.

Bula answered 22/2, 2018 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.