Search code examples
iosobjective-cafnetworkingafnetworking-2

How to make an authenticated POST with parameters in body and in URL?


Due to server constraints, I need to make a POST that includes parameters in both the URL and the body. I'm using AFHTTPRequestOperationManager's HTTPRequestOperationWithRequest method to accomplish this, as I can initialize the URL request with the URL params like:

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:components.URL];

And then I can separately set the body of the POST like:

[request setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];

The problem arises when I've set the AFHTTPRequestOperationManager's requestSerializer to use an Authorization header token. The request comes back as a 401 unauth. However, if I set the request object's header directly like:

[request setValue:self.accessToken forHTTPHeaderField:@"Authorization"];

The call succeeds. Anyone know of a better way to make an authenticated call that sends parameters simultaneously in the body and the URL of the POST? My implementation seems less than ideal.


Solution

  • Unless you need to support iOS6, I think you should move to using AFHTTPSessionManager instead of AFHTTPRequestOperationManager.

    Subclass AFHTTPSessionManager and override:

    - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                                   uploadProgress:(void (^)(NSProgress * _Nonnull))uploadProgressBlock
                                 downloadProgress:(void (^)(NSProgress * _Nonnull))downloadProgressBlock
                                completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {
    
        NSMutableURLRequest *modifiedRequest = request.mutableCopy;    
        NSString *token = [Get your access token];
    
        [modifiedRequest addValue:token forHTTPHeaderField:@"Authorization"];
    
        // Now set up the data task as normal
        return [super dataTaskWithRequest:modifiedRequest
                           uploadProgress:uploadProgressBlock
                         downloadProgress:downloadProgressBlock
                        completionHandler:completionHandler];
    }
    

    It results in the same as your approach (I'm not aware of a better way) - but ensures it happens automatically for all calls.

    Initialise your session manager as an instance of your subclass.

    Then using AFNetworking's POST method, set up your parameters and go:

    NSDictionary *params = @{@"Param1":param1 ? param1 : @"",
                             @"Param2":param2 ? param2 : @""};
    
    [self.sessionManager
     POST:self.serviceEndpointUrl
     parameters:params
     etc..