AFNetworking POST to REST webservice

28,856

Solution 1

These are the essential (stripping out conditions I've made for my own use) lines that ended up satisfying my request to the web service. Thanks for the suggestions @8vius and @mattt !

- (IBAction)loginButtonPressed {        
    NSURL *baseURL = [NSURL URLWithString:@"https://www.example.com/api/class"];

    //build normal NSMutableURLRequest objects
    //make sure to setHTTPMethod to "POST". 
    //from https://github.com/AFNetworking/AFNetworking
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
    [httpClient defaultValueForHeader:@"Accept"];

    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            [usernameTextField text], kUsernameField, 
                            [passwordTextField text], kPasswordField, 
                            nil];

    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" 
          path:@"https://www.example.com/api/class/function" parameters:params];

    //Add your request object to an AFHTTPRequestOperation
    AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] 
                                      initWithRequest:request] autorelease];

    //"Why don't I get JSON / XML / Property List in my HTTP client callbacks?"
    //see: https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ
    //mattt's suggestion http://stackoverflow.com/a/9931815/1004227 -
    //-still didn't prevent me from receiving plist data
    //[httpClient registerHTTPOperationClass:
    //         [AFPropertyListParameterEncoding class]];

    [httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];

    [operation setCompletionBlockWithSuccess:
      ^(AFHTTPRequestOperation *operation, 
      id responseObject) {
        NSString *response = [operation responseString];
        NSLog(@"response: [%@]",response);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"error: %@", [operation error]);
    }];

    //call start on your request operation
    [operation start];
    [httpClient release];
}

Solution 2

Use AFHTTPClient -postPath:parameters:success:failure:, passing your parameters (nested dictionaries/arrays are fine). If you're expecting a plist back, be sure to have the client register AFPropertyListRequestOperation.

In any case, setValue:forHTTPHeaderField: is not what you want here. HTTP headers are for specifying information about the request itself; data is part of the request body. AFHTTPClient automatically converts parameters into either a query string for GET requests or an HTTP body for POST, et al.

Share:
28,856
palmi
Author by

palmi

Updated on February 25, 2020

Comments

  • palmi
    palmi over 4 years

    Brief backstory, our previous developer used ASIHTTPRequest to make POST requests and retrieve data from our webservice. For reasons unknown this portion of our app stopped working. Seemed like good enough time to future proof and go with AFNetworking. REST webservice runs on the CakePHP framework.

    In short I am not receiving the request response string using AFNetworking.

    I know the webservice works because I am able to successfully post data and receive the proper response using curl: curl -d "data[Model][field0]=field0value&data[Model][field1]=field1value" https://example.com/api/class/function.plist

    Per the previous developer's instructions I came up with the following.

    #import "AFHTTPRequestOperation.h"    
    
    …
    
    - (IBAction)loginButtonPressed {
    
        NSURL *url = [NSURL URLWithString:@"https://example.com/api/class/function.plist"];
    
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
        [request setHTTPMethod:@"POST"];
    
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
        [request setValue:[usernameTextField text] forHTTPHeaderField:@"data[User][email]"];
    
        [request setValue:[passwordTextField text] forHTTPHeaderField:@"data[User][password]"];
    
        AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
    
        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {  
    
            NSLog(@"operation hasAcceptableStatusCode: %d", [operation.response statusCode]);
    
            NSLog(@"response string: %@ ", operation.responseString);
    
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    
            NSLog(@"error: %@", operation.responseString);
    
        }];
    
        [operation start];
    
    }
    

    output: operation hasAcceptableStatusCode: 200 response string: a blank plist file

    attempted solution 1: AFNetworking Post Request the proposed solution uses a function of AFHTTPRequestOperation called operationWithRequest. However, when I attempt to use said solution I get a warning "Class method '+operationWithRequest:completion:' not found (return type defaults to 'id'"

    attempted solution 2: NSURLConnection. output: I'm able to print the success log messaged but not the response string. *update - returns blank plist.

    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
    NSString *httpBodyData = @"data[User][email][email protected]&data[User][password]=awesomepassword";
    [httpBodyData dataUsingEncoding:NSUTF8StringEncoding];
    [req setHTTPMethod:@"POST"];
    [req setHTTPBody:[NSData dataWithContentsOfFile:httpBodyData]];
    NSHTTPURLResponse __autoreleasing *response;
    NSError __autoreleasing *error;
    [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
    
    // *update - returns blank plist
    NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil];
    NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    NSLog(@"responseData %@",str);
    
    if (error == nil && response.statusCode == 200) {
        // Process response
        NSLog(@"success");//returns success code of 200 but blank
        NSLog(@"resp %@", response );
    } else {
        // Process error
        NSLog(@"error");
    }
    
  • palmi
    palmi about 12 years
    I resolved this issue but I have a feeling I am still doing something wrong or inefficiently. I'd greatly appreciate it if you had a quick look at my solution. Thanks!
  • mattt
    mattt about 12 years
    Registering for plist operations only affects request operations created using AFHTTPClient -HTTPRequestOperationWithRequest:success:failure:. alloc init-ing AFHTTPRequestOperation is always going to give you an AFHTTPRequestOperation.
  • Ganesh G
    Ganesh G almost 11 years
    @pouria, What is Path here. Is it like a same URL. Please help me i got stuck at Path.
  • palmi
    palmi over 10 years
    @G.Ganesh I'm getting to this a bit late. The Path was simply a method of the class that responded to HTTP POSTs with a given set of params. I hope you resolved your issue.