AFHttpClient post with both parameters and JSON in body - ios

Sorry, but im kinda a newb regarding http post terminology!
I have to post to a webservice that cannot be changed:
The format is as follows:
http://SomeWebAddress/JSON/GetAllFeedsRestfullyWrapped?userToken=FOO
so the parameters are:
key:userToken , value=FOO
In the body i need to put a JSON formatted array like this:
{"feedIds":[1,2,3,4,5,6]}
Im trying to accomplish this with AFNetworking but cannot seem to make it work for this situation.
I have tried both the AFHttpclient and AFJSONReqestIOperation but im not able to combine the request and body correct.
So i hope someone knows how to do this. Help is very much appreciated.

Try that
[[YourHTTPClient sharedHTTPClient] postPath:#"GetAllFeedsRestfullyWrapped?userToken=FOO"
parameters:[NSDictionnary {"feedIds":[1,2,3,4,5,6]}]
success:^(AFHTTPRequestOperation *request, id JSON)
{
}
failure:^(AFHTTPRequestOperation *request, NSError *error)
{
}];

So using Mathieu Hausherr's response as a baseline this was my solution:
NSArray *feedIds = [NSArray arrayWithObject:[NSNumber numberWithInteger:3]];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc]init];
[parameters setObject:feedIds forKey:#"listOfFeedIds"];
[[RssReaderWebserviceApiClient sharedInstance] postPath:#"GetFeedsRestfullyWrapped?userToken=FOO"
parameters:parameters
success:^(AFHTTPRequestOperation *request, id JSON){
LOG_TEST(1,#"Response: %#",JSON);
}
failure:^(AFHTTPRequestOperation *request, NSError *error){
LOG_ERROR(1,#"Error: %#",error);
}];
I use the method postPath:parameters to achieve the post.
I manually set the parameters in the request header and input the bodyparameters from a dictionary.
Encoding is set to JSON.
I anyone wonders the logging is done using NSLogging.It's awesome.

Related

Afnetworking PUT parameters

I'm trying to update some fields with body parametres
NSString *requestString = [NSString stringWithFormat:#"%#/auth/password", self.baseURL ];
[[self managerWithHeaders] PUT:requestString parameters:#{#"foo":#"bar"} success:^(NSURLSessionDataTask *task,id responseObject) {
NSLog(#"%#",responseObject);
} failure:^(NSURLSessionDataTask *task,NSError *error) {
if(failure) failure(error, [self getErrorMessageWithCode:error.code]);
}];
on server this method getting
{"foo"=>"bar", *"password"=>{"foo"=>"bar"}}
But Password is a method name. Why PUT method trying update this parameters?
P.S when i send this request with string (#"%#/auth/password?foo=bar") everything is ok.
As mentioned in the comments; a PUT request puts the parameters into the HTTPBody and not into the URL like a GET request would.
So, add them to your parameters and not to the URL part. Something like this:
[[self managerWithHeaders] PUT:#"example.com/auth parameters:#{#"foo":#"bar", #"password" : #"sdfsdfsff"} success:^(NSURLSessionDataTask *task,id responseObject) {
NSLog(#"%#",responseObject);
} failure:^(NSURLSessionDataTask *task,NSError *error) {
if(failure) failure(error, [self getErrorMessageWithCode:error.code]);
}];
Don't include parameters as part of the URL for PUT requests

AFNetworking POST request with array of JSON objects

So I'm trying to do a post request with an array of JSON parameters sent to a server, here's the code for that
for(USER_ACTIONS *ua in [USER_ACTIONS listRegisterdActions]){
//Create a single JSON object here
[array addObject:jsonString];
}
NSString *dataString = [NSString stringWithFormat:#"[%#]",array.count ?
NSData* data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[#"data"] = data;
[self POST:#"?cmd=log" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];
This works with a single JSON object, but once there are more of them I get the following exception
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (NSConcreteMutableData)'
It's out of the question to do this with a multiple post requests so I need a way to do this with one, my search results on this have not gotten any clear results on how to do this with AFNetworking 2.x so I'd appreciate some pointers on where to go with this.
AFNetworking can automatically change paramter in NSDictionary to JSON.
change your manager's property requestSerializer to AFJSONRequestSerializer the default value is AFHTTPRequestSerializer
AFJSONRequestSerializer is a subclass of AFHTTPRequestSerializer that encodes parameters as JSON using NSJSONSerialization, setting the Content-Type of the encoded request to application/json.
For some reason just using the AFHTTPSessionManager Post function with the constructingBodyWithBlock parameter actually works for some reason. No idea why this is needed because there isn't actually anything in that block, if anyone could tell me why it would be nice.
[self POST:#"?cmd=log" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
//For some reason the request won't work unless this block is included in the function as well, even though nothing is actually done in it
} success:^(NSURLSessionDataTask *task, id responseObject) {
//Success code here
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];

UIAlertView for when fetching JSON fails [duplicate]

This question already has an answer here:
Fetching JSON data after failed retrieval
(1 answer)
Closed 7 years ago.
I'm trying to get this UIAlertView to run when fetching the JSON data fails, but i can't seem to get it to work. I'd appreciate it if someone could show me how to do it or point me in the right direction!
I think you have forget to write failure block.
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", operation.responseString);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
}];
Hope this will help you.
You can write this in your block
NSDictionary *headersCollection=[[(NSDictionary *)operation valueForKey:#"response"]valueForKey:#"allHeaderFields"];
NSMutableDictionary *headers=[headersCollection mutableCopy];
headers[#"statusCode"]=[NSNumber numberWithInteger:operation.response.statusCode];
and then check the status code value. Headers dictionary will provide you the complete header which is returned. If statuscode is 200 everything is OK else you can show your custom message accordingly with different status code values like 400, 415 etc

Easy way to read keys and values from text file on web server?

I was wondering, is there a file format that allows you to store keys and values, and some api that lets you read said file from a web server into a NSDictionary easily? I'm just trying to store 5 or so values associated with keys in a file on the web, so looking for something simple.
I know how to read a simple text file into an NSString, but I was wondering if there is something that lets me do what I described above easily / more efficiently without having to manually prepare the file myself and then write the code to tokenize it, etc.
The file format you need is json. The API you need is AFNetworking. Here is the sample which connect to a server and parse that json to NSDictionary.
//send son info to server
NSDictionary* json = #{
kUserTokenKey : [SOLUser currentUser].token,
kMarkerUserMarkPayIDKey : markerUserMark.objectID,
kCardMarkerPayIDKey : card.objectID,
kCardZipCodeKey: zipCode
};
//create a request url
NSString* requestURL = [NSString stringWithFormat:#"%#%#",kSOLServicesURL,kSOLServicesMarkerPay];
//AFNetworking block to call server api
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager POST:requestURL parameters:json success:^(NSURLSessionDataTask *task, id responseObject) {
[manager invalidateSessionCancelingTasks:YES];
//Recieving object from server and pass to json
NSDictionary* obj = responseObject;
if ([obj[kAPIStatusKey] isEqualToString:kAPIStatusSuccessKey]) {
if (completion) completion(nil);
} else {
NSError* error = [NSError errorWithMessage:obj[kAPIDataKey] code:0];
if (completion) completion(error);
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[manager invalidateSessionCancelingTasks:YES];
LBLog(#"Error: %#", error);
if (completion) completion(error);
}];

Using method parameters

I have a method to download a JSON result from a server regularly so I would like to learn how to input parameters as opposed to keep typing out the same method over and over!
Here is what I have so far:
-(void)downloadData:(NSString *)saveto downloadURL:(NSString *)URL parameters:(NSString *)params{}
It is mostly working ok, except where I am attempting to save my result. I wish to store my result in an array called "locations", I am trying to pass the name locations in the "saveto" NSString, but am not sure how to do so?
Originally I used:
locations =[[NSMutableArray alloc] init];
I would like to somehow pass the name of the array I wish to save to so like this?:
saveto = [[NSMutableArray alloc] init];
Example to run method:
[self downloadData:[NSString stringWithFormat:#"locations"] downloadURL:[NSString stringWithFormat:#"http://test.com:80/test/locations.php"] parameters:[NSString stringWithFormat:#"welcome=hi"]];
You haven't shown us how you're retrieving the data (synchronously or asynchronously?) nor how you're building that request (it's curious that params and saveto and URL are all string parameters).
But I'd suggest doing it asynchronously (since you never want to block the main queue). And in that case, you provide a "block" parameter that the caller can specify the block of code to run when the download is done.
So, you might have downloadData that looks something like:
- (void)downloadDataWithURL:(NSURL *)URL parameters:(NSDictionary *)parameters completion:(void (^)(NSArray *array, NSError *error))completion
{
// build your request using the URL and parameters however you want
NSURLRequest *request = ...;
// now issue the request asynchronously
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!data) {
completion(nil, connectionError);
return;
}
NSError *parseError = nil;
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
completion(array, parseError);
}];
}
And can be invoked as:
NSURL *URL = [NSURL URLWithString:#"http://test.com:80/test/locations.php"];
NSDictionary *parameters = #{#"welcome" : #"hi"};
[self downloadDataWithURL:URL parameters:parameters completion:^(NSArray *array, NSError *error) {
if (error) {
NSLog(#"downloadDataWithURL error: %#", error);
return;
}
self.locations = array;
}];
FYI, I made the URL to be a NSURL object (to conform to common practice). I also made the parameters a NSDictionary (so that if you're making a GET request or POST request of type application/x-www-form-urlencoded, you can more easily do the necessary CFURLCreateStringByAddingPercentEscapes; if it's JSON request, this also makes it easier to make a proper JSON request).
But feel free to change the parameters URL and parameters to be whatever type makes sense for your particular implementation, but hopefully this illustrates the idea. Add an additional completion block parameter which will be the block of code that will be run when the download is done, and then the caller do whatever it wants with the results.
You should not reinvent the wheel and you should use one of the frameworks like AFNetworking or RestKit to do this stuff for you. In addition to doing the work for you it gives you very powerful tools like reachability and error handling and most importantly it handles converting to and from JSON (and many other formats). When you use AFNetworking you get an NSDictionary called responseObject that you can use in many ways including setting an NSString. Most of the time you will simply use that dictionary as the dataSource for your UI so all of the work is done for you.
AFNetworking code looks like this:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://example.com/resources.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
As you can see in only a couple of lines of code you handle success, failure, and the creation of an object with all your info. No need for [[NSDictionary alloc] init]
This is one of the many many great tutorials on AFNetworking

Resources