user2001457
user2001457

Reputation: 165

JSON format issue in PHP REST service receiving POST from AFNetworking 2.0

I have a situation where I POST a JSON string from my iOS code using AFNetworking 2.0 code. My client code looks like this:

NSURL *url = [NSURL URLWithString:BaseURLString];
NSString *jsonString = [[NSString alloc] initWithData:jsonPayloadForProject encoding:NSUTF8StringEncoding];

NSDictionary *parameters = @{@"project": jsonString};

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]       initWithBaseURL:url];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

[manager POST:@"service.php" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
    NSLog(@"%@", [responseObject description]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"POST JSON for Project Error"
                                                        message:[error localizedDescription]
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
    [alertView show];
}];

The JSON looks like this:

{
  "Maps" : [
    {
      "Markers" : [
        {
          "marker_tag" : -790386438,
          "location_y" : 182,
          "location_x" : 344
        },
        {
          "marker_tag" : 451496476,
          "location_y" : 267,
          "location_x" : 150.5
        }
      ],
      "image_string" : "EC817509-DE49-4914-840E-5E407571F6AE.jpeg",
      "order_num" : 0,
      "name" : "Blah1",
      "id" : "EC817509-DE49-4914-840E-5E407571F6AE"
    },
    {
      "Markers" : [
        {
          "marker_tag" : -79601351,
          "location_y" : 377,
          "location_x" : 486.5,
          "image_id" : "Blah2",
          "map_id" : "146C1C09-5AE0-4E4C-83C8-B7EAA8F28A9A"
        }
      ],
      "image_string" : "146C1C09-5AE0-4E4C-83C8-B7EAA8F28A9A.jpeg",
      "order_num" : 0,
      "name" : "1st floor",
      "id" : "146C1C09-5AE0-4E4C-83C8-B7EAA8F28A9A"
    }
  ],
  "longitude" : "-222.222222",
  "latitude" : "33.33333"
}

When I read the JSON string on the server in my php code using

$json_str = file_get_contents('php://input');

When I do that, I get the following string:

{ "project" = '{ \n \"Maps\" : [ \n { \n \"Markers\" : [ \n { \n \"marker_tag\n : = -790386438, \n ....

My question is that when I do the following, I get nothing.

$array_str = json_decode($json_str, true);

What is the best way to put that into an array to parse for data? How can I get back the original JSON string I sent from my client?

Upvotes: 1

Views: 742

Answers (1)

Rob
Rob

Reputation: 437582

A couple of issues

  1. Your AFHTTPSessionManager is using the default AFJSONResponseSerializer but merely overriding the acceptableContentTypes. You would only do that if your server code was really returning JSON and failing to specify so in the Content-Type header.

    • If the server is really not returning JSON, rather than changing acceptableContentTypes, you should simply use AFHTTPSessionManager

      manager.responseSerializer = [AFHTTPResponseSerializer serializer];
      
    • or have the server return JSON and make sure it specifies the correct Content-Type header:

      <?php
      
      $json_str = file_get_contents('php://input');
      $json = json_decode($json_str, true);
      
      header('Content-Type: application/json');
      
      $result = array("received" => $json);
      echo json_encode($result);
      
      ?>
      

      Having done that, I can now simply remove the acceptableContentTypes line from the client code altogether and continue to use the default AFJSONResponseSerializer.

  2. The demonstrated mechanism for building parameters is incorrect. You are creating a JSON dictionary with only one item in it, which itself is a string representation of JSON.

    Instead of putting a string representation within the dictionary, I would suggest that you want to put the actual dictionary within the dictionary. So, if you really have a NSData of the JSON, convert it back to the nested NSDictionary/NSArray structure:

    NSError *error;
    id jsonPayload = [NSJSONSerialization JSONObjectWithData:jsonPayloadData options:0 error:&error];
    NSAssert(jsonPayload, @"json parsing error: %@", error);
    
    NSDictionary *parameters = @{@"project": jsonPayload};
    

    Now, most likely, it will be a little silly to create a NSData using dataWithJSONObject, only to turn around and extract it back out, but rather you'd just use that original NSDictionary within parameters, but hopefully this illustrates the point.

So, pulling that all together, assuming you change the server code to return properly formatted JSON response, as outlined above, the client code now becomes:

NSError *error;
id jsonPayload = [NSJSONSerialization JSONObjectWithData:jsonPayloadData options:0 error:&error];
NSAssert(jsonPayload, @"json parsing error: %@", error);

NSDictionary *parameters = @{@"project": jsonPayload};

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:url];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

[manager POST:@"service.php" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
    NSLog(@"%@", [responseObject description]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    NSLog(@"error=%@", error);
}];

If you do that, you will successfully send your JSON request to the server, it will be parsed, inserted into a new associative array, converted back to JSON and returned to the client app, which will use the default AFJSONResponseSerializer to parse it and log it.

Upvotes: 1

Related Questions