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?
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.
Related
I have tried several StackOverflow questions, and I caanot find the correct answer on this. I am using the POSTMAN plugin for Chrome to check my REST calls and I cannot figure out why I cannot read the response. In the comments you will see all the different attempts I have made to get the response.
NSDictionary* session_params = #{SESSION_USERNAME_KEY:SESSION_USERNAME_VALUE, SESSION_PASSWORD_KEY:SESSION_PASSWORD_VALUE};
NSURL* url = [NSURL URLWithString:SESSION_URL];
RKObjectManager* objectManager = [RKObjectManager managerWithBaseURL:url];
//GET THE **** THING TO INTERPRET A TEXT response
//[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:RKMIMETypeTextXML];
//[objectManager setAcceptHeaderWithMIMEType:#"text/html"];
//[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeTextXML];
//[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:#"text/html"];
//[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/html"];
//[objectManager setRequestSerializationMIMEType:#"text/html"];
//END
NSMutableURLRequest* request = [objectManager requestWithObject:nil method:RKRequestMethodPOST path:SESSION_URL parameters:session_params];
RKObjectRequestOperation* operation = [objectManager
objectRequestOperationWithRequest:request success:^(RKObjectRequestOperation* operation, RKMappingResult* result)
{
NSLog(#"RESULT [%#]", result);
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"ERROR [%#]", error);
}];
[operation start];
I think the most irritating thing is that the stuff I need is contained in the NSLocalizedRecoverySuggestion value. It is a session key I require.
OUTPUT:
E restkit.network:RKObjectRequestOperation.m:547 Object request failed: Underlying HTTP request operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html" UserInfo=0x1c52aed0 {NSLocalizedRecoverySuggestion=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw, AFNetworkingOperationFailingURLRequestErrorKey=, NSErrorFailingURLKey=http://..., NSLocalizedDescription=Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=}
2014-02-17 14:54:20.808 AppName[5600:6403] E restkit.network:RKObjectRequestOperation.m:213 POST 'http://...' (200 OK / 0 objects) [request=0.0000s mapping=0.0000s total=0.1925s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html" UserInfo=0x1c52aed0 {NSLocalizedRecoverySuggestion=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw, AFNetworkingOperationFailingURLRequestErrorKey=, NSErrorFailingURLKey=http://..., NSLocalizedDescription=Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=}
CODE THAT WORKED
Thanks to Wain for pointing me on the correct path there. I am a little disappointed that RestKit cannot handle such a simple request, and I need RestKit because this is just a session token to calling the other methods, but whatever works I guess:
NSDictionary* session_params = #{SESSION_USERNAME_KEY:SESSION_USERNAME_VALUE, SESSION_PASSWORD_KEY:SESSION_PASSWORD_VALUE};
NSURL* url = [NSURL URLWithString:SESSION_URL];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:SESSION_URL parameters:session_params];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString* response = [operation responseString];
NSLog(#"response: %#",response);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", [operation error]);
}];
[operation start];
This bit:
"Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html"
tells you that you have told RestKit to expect form-urlencoded or json, but that the server is returning html.
You would probably want to use setAcceptHeaderWithMIMEType with JSON mime type to tell the server what you want back. But, in this case you probably just shouldn't be using RestKit.
RestKit is for mapping arbitrary JSON / XML data into your data model. You just have a key coming back. No mapping is required. So, don't use RestKit, use AFNetworking instead (which you have full access to because RestKit uses it internally.
Thanks to Wain and Quintin, this was quite useful to me :)
I think some names changed in more recent versions of Restkit or AFNetworking. I used AFNetworking as explained in other answers since the server did not return json but empty plain/text instead. This was only on a particular endpoint where I was looking for a token in the headers of the response.
Sharing my piece of code here too:
-(void) find_some_token_with_success:(void (^)(AFRKHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFRKHTTPRequestOperation *operation, NSError *error))failure {
NSURL *baseURL = [NSURL URLWithString:#"https://example.com"];
AFRKHTTPClient *client = [AFRKHTTPClient clientWithBaseURL:baseURL];
[client setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
[client setDefaultHeader:#"some_custom_header" value:#"some_custom_value"];
NSMutableURLRequest *request = [client requestWithMethod:#"GET" path:#"/api/v1/some_non_json_endpoint" parameters:nil];
AFRKHTTPRequestOperation *operation = [[AFRKHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:success failure:failure];
[operation start];
}
Then I used something like this to get the header I was looking for:
-(void) get_the_token:(void (^)(NSString *token))withTokenCallback failure:(void (^)(AFRKHTTPRequestOperation *operation, NSError *error))failure {
[self xsrftoken_with_success:^(AFRKHTTPRequestOperation *operation, id responseObject) {
NSString *token = [self get_the_token_from_response:[operation response]];
withTokenCallback(token);
} failure:failure];
}
-(NSString *) get_the_token_from_response: (NSHTTPURLResponse *) response;
{
NSDictionary *headerDictionary = response.allHeaderFields;
NSString *token = [headerDictionary objectForKey:#"SOME-TOKEN-KEY"];
return token;
}
So all of this can simply be used like this:
- (void)testGetSometokenInARequest
{
XCTestExpectation *expectation = [self expectationWithDescription:#"Query timed out."];
[[SomeRequestWithoutJsonResponse alloc]
get_the_token:^(NSString *token) {
[expectation fulfill];
NSLog(#"token: %#", token);
// this token should be 100 characters long
XCTAssertTrue([token length] == 100);
}
failure:^(AFRKHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", [operation error]);
}];
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
In other words, get_the_token takes a callback with the desired token and a failure callback.
Make sure you still include <RestKit/RestKit> so you have access to Restkit's AFNetowkring :)
Alternative working solution using restkit:
RestKit: How to handle empty response.body?
And you register a serializer for that kind of Mimetype like this:
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];
I am doing an instagram appliaction. In that I need to post like on Images. I am not able to post . I am following instgram API. We need to use following url
https://api.instagram.com/v1/media/{media-id}/likes
We need to set media id like
https://api.instagram.com/v1/media/649114513807113248_1032025382/likes
media id = 649114513807113248_1032025382
My code to post:
NSString *urlString = [NSString stringWithFormat:#"https://api.instagram.com/v1/media/649114513807113248_1032025382/likes"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
NSURLConnection *connection= [[NSURLConnection alloc] initWithRequest:request
delegate:self];
[connection start];
But like is not posting. Can anyone help me ?
You can post your data in better way using AFNetworking framework. Samples are also provided on github.
http://afnetworking.com/
MGInstagram and DMActivityInstagram is a iOS Utility for posting Images to Instagram from your app.
// Uses our instagram instance to do a request
- (void) postMessage:(NSString *)message mediaId:(NSString *)mediaId {
NSString* methodName = [NSString stringWithFormat:#"media/%#/comments", mediaId];
NSMutableDictionary* params = #{"text" : message};
[m_instagram requestWithMethodName:methodName params:params httpMethod:#"POST" delegate:self];
}
// IGRequestDelegate method that is called once we get a response
- (void)request:(IGRequest *)request didLoad:(id)result {
// post message was ok
}
- (void)request:(IGRequest *)request didFailWithError:(NSError *)error {
// post message fails
}
Reference from https://github.com/crino/instagram-ios-sdk/issues/27
if you are share the images to social network use below link it have sample app with tutorial
share-an-image-on-instagram-in-ios/
better to use AFNetworking for post, bellow is a sample , please have a look
-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock
{
NSMutableURLRequest *apiRequest =
[self multipartFormRequestWithMethod:#"POST"
path:kAPIPath
parameters:params
constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
//TODO: attach file if needed
}];
AFJSONRequestOperation* operation = [[AFJSONRequestOperation alloc] initWithRequest: apiRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//success!
completionBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//failure :(
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
[operation start];
}
I am taking over an old iOS project from developers no longer part of the project - the app is getting a rewrite and with that I am going to support iOS7 and upwards only.
So, I wanted to use AFNetworking 2.0 instead of ASIHTTPRequest - the reason behind this is NSURLSeesion. AFNetworking 2.0 supports NSURLSession and with that I can get my app to download content in the background at opportunistic times (According to Apple - NSURLSession must be used and Background Fetch mode turned on, for this to work? )
Let me start out by saying I am a new developer to iOS and networking stuff goes a little over my head - but I am determined to learn more about it and as much as I can. I have read AFNetworking documentation as well, but I fear since some of the terminology escapes me (Request, Response, Sterilisation, etc) - I am not grasping them 100%.
So, I took a look at the ASIHTTPRequest code the previous developer used to, from what I can see, build a GET / POST request - This is the code they used:
+ (ASIHTTPRequest*) buildRequest: (NSString*) url RequestType: (NSString*) requestType
PostData: (NSString*) postData
Host: (NSString*) host
ContentType: (NSString*) contentType
SoapAction: (NSString*) soapAction
RequestProperties: (NSDictionary*) requestProperties
{
NSURL *url = [NSURL URLWithString: url];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:u] autorelease];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestWentWrong:)];
[request setTimeOutSeconds:20];
[request setQueuePriority:NSOperationQueuePriorityVeryHigh];
if (host != nil)
[request addRequestHeader: #"Host" value: host];
if (contentType != nil)
[request addRequestHeader: #"Content-Type" value: contentType];
if (soapAction != nil)
[request addRequestHeader: #"SOAPAction" value:soapAction];
if (requestType != nil)
[request setRequestMethod: requestType];
if (postData != nil)
{
NSMutableData* mPostData = [NSMutableData dataWithData:[postData dataUsingEncoding:NSUTF8StringEncoding]];
NSString *msgLength = [NSString stringWithFormat:#"%d", [postData length]];
[request setPostBody: mPostData];
[request addRequestHeader: #"Content-Length" value:msgLength];
}
if (requestProperties != nil)
{
for (int i = 0; i < [[requestProperties allKeys] count]; i++)
{
[request addRequestHeader:[[requestProperties allKeys] objectAtIndex: i] value: [requestProperties objectForKey:[[requestProperties allKeys] objectAtIndex: i]]];
}
}
return request;
}
I'm trying to understand this code and upgrade it to use AFNetworking V2.0 instead. I assume, just replacing ASIHTTPRequest with AFHTTPRequestOperation will not do the trick, correct?
I have been given some help and also managed to do a lot of digging around to see how I can get this right.
I made the method simpler - as I did not need Soap / Content-type, etc - just urlParamerters and some basic stuff:
This is the answer I came up with:
+ (AFHTTPSessionManager *) buildRequest: (NSString*) url RequestType: (NSString*) requestType PostDataValuesAndKeys: (NSDictionary*) postData RequestProperties: (NSDictionary*) requestProperties
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
if ([requestType isEqualToString:#"GET"])
{
[manager GET:url parameters:postData success:^(NSURLSessionDataTask *dataTask, id responseObject){
//Success
NSLog (#"Success");
NSData *xmlData = responseObject;
NSLog(#"Got XML Data: %#", xmlData);
}
failure:^(NSURLSessionDataTask *dataTask, NSError *error){
//Failure
NSLog (#"Failure");
}];
}else if ([requestType isEqualToString:#"GT"]){
[manager POST:url parameters:postData success:^(NSURLSessionDataTask *dataTask, id responseObject){
//Success
}
failure:^(NSURLSessionDataTask *dataTask, NSError *error){
//Failure
NSLog (#"Failure");
}];
}
return manager;
}
It will work for what I need it to do - but I am not sure if it's the best way to do it.
I couldn't see how I could detect the requestType other thank with looking at the NSString value. I looked into the AFHTTPSessionManager.h file for some clues on what to do with that - Matt suggests overriding the GET / POST methods if I want them done differently - per his comments in the header file:
Methods to Override
To change the behavior of all data task operation construction, which
is also used in the GET / POST / et al. convenience methods,
override dataTaskWithRequest:completionHandler:.
Also there is a requestSerializer property in that file - which you could use to detect the type of request - however it's implementation goes to the super class: AFURLSessionManager
In that class - there is a requestWithMethodmethod.
So, I tried to do this instead:
If I try implement that method - then I am not using the convince methods in AFHTTPSessionManager:
(NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(NSDictionary *)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
Unless I have that completely wrong. After that I decided to just check the requestType using [NSString isEqualToString]
I have an iOS + Rails 3.1 app, and I'm using AFIncrementalStore for the client-server communication.
I have implemented Token Authentication on my Rails server according to this tutorial: http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/
I now want to include the &auth_token=XXXXXXXX in every request from client to server, including POST requests. How would I do that? I haven't found the solution in this related post: Using AFIncrementalStore with an Auth token
UPDATE: this is my first code attempt, but doesn't seem to send the auth_token:
(inside my AFIncrementalStoreHTTPClient sub-class)
- (NSMutableURLRequest *)requestForFetchRequest:(NSFetchRequest *)fetchRequest withContext:(NSManagedObjectContext *)context {
NSMutableURLRequest *request = [[super requestForFetchRequest:fetchRequest withContext:context] mutableCopy];
NSMutableString *requestBody = [[NSMutableString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding];
[requestBody appendFormat:#"&%#=%#", #"auth_token", #"xkT2eqqdoNp5y4vQy7xA"];
[request setHTTPBody:[requestBody dataUsingEncoding:NSUTF8StringEncoding]];
return request;
}
UPDATE: I skimmed your question (sorry!), and my sample code below works for a regular AFHTTPClient, but not AFIncrementalStore. The same basic approach will work, though, and there's sample code at this answer that should point you in the right direction.
You can't just append &auth_token=whatever to the end of your HTTP body in all cases.
You probably want to override your getPath... and postPath... methods with something like:
- (void)getPath:(NSString *)path
parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
if (parameters) {
// Make a mutable copy and add the "token" parameter to the dictionary
NSMutableDictionary *mutableParams = [parameters mutableCopy];
[mutableParams setObject:#"whatever" forKey:#"token"];
parameters = [NSDictionary dictionaryWithDictionary:mutableParams];
} else {
parameters = #{#"token" : #"whatever"};
}
[super getPath:path parameters:parameters success:success failure:failure];
}
This approach will allow AFNetworking to appropriately encode your parameters depending on your specific request and encoding settings.
If you are rolling your own AFHTTPRequestOperation objects instead of using the convenience methods (you probably aren't), just make sure you include the token in parameters before you create your NSURLRequest like so:
NSURLRequest *request = [self requestWithMethod:#"GET" path:path parameters:parameters];
First of all, I realize that for a PUT request the request parameters should be passed in the request body. However, I am working with an API (which I am only consuming, not developing) that expects the request parameters to be appended as the query string for a PUT request.
I am making use of a subclass of AFHTTPClient. For the particular PUT request that I am referring to, I make use of getPath:parameters:success:failure:.
The solution that I have found so far is manually constructing the path variable to include the parameters I want to pass. Of course, this is not ideal and I was wondering if there is another option that is less error prone.
In short, is there a way to send a PUT request using AFHTTPClient (a subclass of) with the passed parameters appended (and encoded) as the query string (just like a GET request)?
The getPath:parameters:success:failure method inside AFHTTPClient.m calls requestWithMethod:path:parameters. Inside the latter method, the HTTP method is checked against certain values to decide how to append the parameters to the request. As you can see, by default, the parameters should only be appended to the URL in case of a GET, HEAD or DELETE request. Since you need them to be appended to the URL in case of a PUT request too, modify the requestWithMethod:path:parameters like this:
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
path:(NSString *)path
parameters:(NSDictionary *)parameters
{
NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:url] autorelease];
[request setHTTPMethod:method];
[request setAllHTTPHeaderFields:self.defaultHeaders];
if ([method isEqualToString:#"GET"] || [method isEqualToString:#"HEAD"]) {
[request setHTTPShouldUsePipelining:YES];
}
if (parameters) {
if ([method isEqualToString:#"GET"] || [method isEqualToString:#"HEAD"] || [method isEqualToString:#"DELETE"] || [method isEqualToString:#"PUT"]) {
url = [NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:[path rangeOfString:#"?"].location == NSNotFound ? #"?%#" : #"&%#", AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding)]];
[request setURL:url];
} else {
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding));
switch (self.parameterEncoding) {
case AFFormURLParameterEncoding:;
[request setValue:[NSString stringWithFormat:#"application/x-www-form-urlencoded; charset=%#", charset] forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]];
break;
case AFJSONParameterEncoding:;
[request setValue:[NSString stringWithFormat:#"application/json; charset=%#", charset] forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[AFJSONStringFromParameters(parameters) dataUsingEncoding:self.stringEncoding]];
break;
case AFPropertyListParameterEncoding:;
[request setValue:[NSString stringWithFormat:#"application/x-plist; charset=%#", charset] forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[AFPropertyListStringFromParameters(parameters) dataUsingEncoding:self.stringEncoding]];
break;
}
}
}
return request;
}
You can just do what the code in datwalk's answer is doing without modifying the underlying AFNetworking code. Use AFNetworking to create a path that includes URL parameters:
NSDictionary *mutableParameters = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"csv",#"format", #"0",#"level", #"2013-10-25", #"keydate", nil];
NSString *urlPath = [NSString stringWithFormat:#"applications/%#/Planning?%#", name, AFQueryStringFromParametersWithEncoding(mutableParameters, NSUTF8StringEncoding)];
NSString *apiFunctionPath = [urlPath stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[self putPath:apiFunctionPath
parameters:nil
success:^(AFHTTPRequestOperation *operation, id XML) {
NSLog(#"%#",XML);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#",error);
}];
For the case of my API, changing the encoding of the AFHTTPClient object solved the issue:
myAFHTTPClient.parameterEncoding = AFJSONParameterEncoding;