How to send json data in the Http request using NSURLRequest

118,175

Solution 1

Here's what I do (please note that the JSON going to my server needs to be a dictionary with one value (another dictionary) for key = question..i.e. {:question => { dictionary } } ):

NSArray *objects = [NSArray arrayWithObjects:[[NSUserDefaults standardUserDefaults]valueForKey:@"StoreNickName"],
  [[UIDevice currentDevice] uniqueIdentifier], [dict objectForKey:@"user_question"],     nil];
NSArray *keys = [NSArray arrayWithObjects:@"nick_name", @"UDID", @"user_question", nil];
NSDictionary *questionDict = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

NSDictionary *jsonDict = [NSDictionary dictionaryWithObject:questionDict forKey:@"question"];

NSString *jsonRequest = [jsonDict JSONRepresentation];

NSLog(@"jsonRequest is %@", jsonRequest);

NSURL *url = [NSURL URLWithString:@"https://xxxxxxx.com/questions"];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
             cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


NSData *requestData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding];

[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody: requestData];

NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
 receivedData = [[NSMutableData data] retain];
}

The receivedData is then handled by:

NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [jsonString JSONValue];
NSDictionary *question = [jsonDict objectForKey:@"question"];

This isn't 100% clear and will take some re-reading, but everything should be here to get you started. And from what I can tell, this is asynchronous. My UI is not locked up while these calls are made. Hope that helps.

Solution 2

I struggled with this for a while. Running PHP on the server. This code will post a json and get the json reply from the server

NSURL *url = [NSURL URLWithString:@"http://example.co/index.php"];
NSMutableURLRequest *rq = [NSMutableURLRequest requestWithURL:url];
[rq setHTTPMethod:@"POST"];
NSString *post = [NSString stringWithFormat:@"command1=c1&command2=c2"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];
[rq setHTTPBody:postData];
[rq setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:rq queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
 {
     if ([data length] > 0 && error == nil){
         NSError *parseError = nil;
         NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
         NSLog(@"Server Response (we want to see a 200 return code) %@",response);
         NSLog(@"dictionary %@",dictionary);
     }
     else if ([data length] == 0 && error == nil){
         NSLog(@"no data returned");
         //no data, but tried
     }
     else if (error != nil)
     {
         NSLog(@"there was a download error");
         //couldn't download

     }
 }];

Solution 3

I would suggest to use ASIHTTPRequest

ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier. It is written in Objective-C and works in both Mac OS X and iPhone applications.

It is suitable performing basic HTTP requests and interacting with REST-based services (GET / POST / PUT / DELETE). The included ASIFormDataRequest subclass makes it easy to submit POST data and files using multipart/form-data.


Please note, that the original author discontinued with this project. See the followring post for reasons and alternatives: http://allseeing-i.com/%5Brequest_release%5D;

Personally I am a big fan of AFNetworking

Solution 4

Most of you already know this by now, but I am posting this, just incase, some of you are still struggling with JSON in iOS6+.

In iOS6 and later, we have the NSJSONSerialization Class that is fast and has no dependency on including "outside" libraries.

NSDictionary *result = [NSJSONSerialization JSONObjectWithData:[resultStr dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; 

This is the way iOS6 and later can now parse JSON efficiently.The use of SBJson is also pre-ARC implementation and brings with it those issues too if you are working in an ARC environment.

I hope this helps!

Solution 5

Here is a great article using Restkit

It explains on serializing nested data into JSON and attaching the data to a HTTP POST request.

Share:
118,175

Related videos on Youtube

Toran Billups
Author by

Toran Billups

Swiss Army Knife: Elixir, React & Tailwind

Updated on July 05, 2022

Comments

  • Toran Billups
    Toran Billups almost 2 years

    I'm new to objective-c and I'm starting to put a great deal of effort into request/response as of recent. I have a working example that can call a url (via http GET) and parse the json returned.

    The working example of this is below

    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
        [responseData setLength:0];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
        [responseData appendData:data];
    }
    
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
      NSLog([NSString stringWithFormat:@"Connection failed: %@", [error description]]);
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
        [connection release];
      //do something with the json that comes back ... (the fun part)
    }
    
    - (void)viewDidLoad
    {
      [self searchForStuff:@"iPhone"];
    }
    
    -(void)searchForStuff:(NSString *)text
    {
      responseData = [[NSMutableData data] retain];
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.whatever.com/json"]];
        [[NSURLConnection alloc] initWithRequest:request delegate:self];
    }
    

    My first question is - will this approach scale up? Or is this not async (meaning I block the UI thread while the app is waiting for the response)

    My second question is - how might I modify the request part of this to do a POST instead of GET? Is it simply to modify the HttpMethod like so?

    [request setHTTPMethod:@"POST"];
    

    And finally - how do I add a set of json data to this post as a simple string (for example)

    {
        "magic":{
                   "real":true
                },
        "options":{
                   "happy":true,
                    "joy":true,
                    "joy2":true
                  },
        "key":"123"
    }
    

    Thank you in advance

  • Toran Billups
    Toran Billups over 13 years
    Everything looks good except the this line [dict objectForKey:@"user_question"], nil]; -- dict is not declared in your sample. Is this just a simple dictionary or something special?
  • Mike G
    Mike G over 13 years
    Sorry about that. Yes, "dict" is just a simple dictionary that I load from the iOS users documents.
  • Rob
    Rob over 11 years
    This is using NSDictionary instance method JSONRepresentation. I might suggest I using NSJSONSerialization class method dataWithJSONObject, instead of the json-framework.
  • respectTheCode
    respectTheCode almost 11 years
    It is more efficient to convert the NSUInteger to an NSString through an NSNumber like [[NSNumber numberWithUnsignedInt:requestData.length] stringValue].
  • CouchDeveloper
    CouchDeveloper over 10 years
    @MikeG Fixed a long standing and so far unnoticed bug in the code sample. Sorry, for editing your post ;)
  • ahmad
    ahmad about 10 years
    the question was about POST
  • auco
    auco about 10 years
    no, the first part of the question is about asynchronicity and there is no answer here that answers that. Cheers for the downvote.
  • Satyam
    Satyam about 10 years
    Can we achieve the same using GET instead of POST?
  • SamChen
    SamChen about 9 years
    content type = "application/x-www-form-urlencoded" did the trick. Thanks
  • Steve Moser
    Steve Moser over 8 years
    MikeG Removed external dependency referred to by @Rob.
  • Steve Moser
    Steve Moser over 8 years
    @Rob well my edit was rejected 3 to 2 so I made my edit an answer here:stackoverflow.com/a/33505940/142358
  • Deepak Badiger
    Deepak Badiger about 8 years
    i was spending too much time investigating the reason for my nil response. This post helped me, especially setting the "content-type" and "content-length" along with "accept" to "application/json". This post has resolved my issue of nil data being returned from the web api. Thanks for the post.
  • Gajendra K Chauhan
    Gajendra K Chauhan almost 7 years
    Nice answer. I used "application/json" in my case
  • arniotaki
    arniotaki almost 5 years
    Critical warning: 'initWithRequest:delegate:' is deprecated: first deprecated in iOS 9.0 - Use NSURLSession (see NSURLSession.h)