Search code examples
iosxmlxml-rpcafnetworkinggdataxml

AFNetworking with GDataXML as HTTPBody for XML-RPC API


I am attempting to use AFNetworking with an XML-RPC based API while using GDataXML as my XML parsing and creation class.

I have successfully written some methods that output a proper XML request according to the spec of the API, I have also tested this XML request using apigee console and verified I get a correct response back every time with the apigee console and the API.

Now comes AFNetworking, I have the following code written which sometimes, but rarely works.

NSMutableURLRequest *request = [[FZAPIClient sharedClient] requestForDataServiceQueryOnTable:@"Contact" usingQueryData:@{ @"LastName" : @"Wagner" } forFields:@[ @"FirstName", @"LastName" ] withLimit:1000 forPage:0];

AFHTTPRequestOperation *operation = [[FZAPIClient sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {

    NSError *error = nil;
    GDataXMLDocument *opdoc = [[GDataXMLDocument alloc] initWithData:[[operation request] HTTPBody] options:0 error:&error];

    if (error) {
        NSLog(@"Error creating XML: %@", error);
    }

    GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:responseObject options:0 error:nil];
    GDataXMLElement *element = [doc rootElement];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [FZAPIErrorHandler handleError:error];
}];

[operation start];

Implementation for - (NSMutableURLRequest *)requestForDataServiceQueryOnTable:(NSString *)table usingQueryData:(NSDictionary *)queryData forFields:(NSArray *)fields withLimit:(NSInteger)limit forPage:(NSInteger)page;

- (NSMutableURLRequest *)requestForDataServiceQueryOnTable:(NSString *)table
                                            usingQueryData:(NSDictionary *)queryData
                                                 forFields:(NSArray *)fields
                                                 withLimit:(NSInteger)limit
                                                   forPage:(NSInteger)page {
    GDataXMLDocument *xmlDocument = [FZXMLGenerator requestForDataServiceQueryOnTable:table
                                                                      usingQueryData:queryData
                                                                           forFields:fields
                                                                           withLimit:limit
                                                                             forPage:page];
    NSMutableURLRequest *request = [self requestWithMethod:@"POST" path:@"" parameters:nil];
    [request setHTTPBody:[xmlDocument XMLData]];
    [request setHTTPMethod:@"POST"];

    return request;
}

When the request works, I get an excepted response.

When the request doesn't work (which is 99% of the time) I get the following response.

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
   <fault>
      <value>
         <struct>
            <member>
               <name>faultCode</name>
               <value>
                  <i4>0</i4>
               </value>
            </member>
            <member>
               <name>faultString</name>
               <value>Failed to parse XML-RPC request: Premature end of file.</value>
            </member>
         </struct>
      </value>
   </fault>
</methodResponse>

This makes me suspect something is happening to the HTTPBody property, I have added logging just about everywhere I can think and see that the XML is indeed attached to the request when it is fired. It is also still accessible via the operation in the completion block.

Any ideas?


Solution

  • It looks like it was as simple as setting the content type on the request.

    Updating the method to

    - (NSMutableURLRequest *)requestForDataServiceQueryOnTable:(NSString *)table
                                                usingQueryData:(NSDictionary *)queryData
                                                     forFields:(NSArray *)fields
                                                     withLimit:(NSInteger)limit
                                                       forPage:(NSInteger)page {
        GDataXMLDocument *xmlDocument = [FZXMLGenerator requestForDataServiceQueryOnTable:table
                                                                          usingQueryData:queryData
                                                                               forFields:fields
                                                                               withLimit:limit
                                                                                 forPage:page];
        NSMutableURLRequest *request = [self requestWithMethod:@"POST" path:@"" parameters:nil];
        [request setHTTPBody:[xmlDocument XMLData]];
        [request setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];
    
        return request;
    }
    

    Solved the problem, notice the line [request setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];

    To make this global on all requests I added the line, [self setDefaultHeader:@"Content-Type" value:@"application/xml"]; to my - (id)initWithBaseURL:(NSURL *)url; implementation.