How to add some parameters to a JSON request? - ios

Usually, to download a JSON, I use AFNetworking creating a singleton with this code
- (void)getJSON {
NSURLRequest * request =
[NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://URL"]];
AFJSONRequestOperation * operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSArray * js = JSON;
[_delegate dati:js];
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * filePath = [[paths lastObject] stringByAppendingPathComponent:#"downloaded.json"];
NSData * data = [NSJSONSerialization dataWithJSONObject:JSON
options:NSJSONWritingPrettyPrinted
error:NULL];
[data writeToFile:filePath
atomically:YES];
}];
[operation start];
}
and calling this code in View Controller
[[DataManager sharedClass] getJSON];
and it works, but now I need to send (post) some parameters (as an authorization code, GPS coordinates, user's mail or something similar) into the request to the server to receive a specific JSON. Server is already configured and it works fine, but I can't find a guide to modify my code to do that. Does somebody knows how to proceed?

This is an example of posting data to server using JSON, for example the json is below:
NSDictionary *json = #{#"authorization_code": yourAuthorizationCode,#"gps": #{#"lat": latitude,#"lng": longitude},#"email":email};
JSON Posting
Posting on server depends also on your server requirements, so if it requires a JSON to post, this is the way:
//Create an AFHTTPRequestOperationManager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//Depending if you need a HTTP header, you create one
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSString *yourAuthorizationCode;
NSString *latitude;
NSString *longitude;
NSString *email;
//My data to be posted via JSON
NSDictionary *json = #{#"authorization_code": yourAuthorizationCode,#"gps": #{#"lat": latitude,#"lng": longitude},#"email":email};
//Sending Post Method, with parameter JSON
[manager POST:#"http://myphp.com/api/v1/profile" parameters:json success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"JSON: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error at creating post: %#", error);
}];
Parameters posted via URL
In this method parameters are passed in URL, and you post them to server in URL form
//Create an AFHTTPRequestOperationManager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *yourAuthorizationCode;
NSString *latitude;
NSString *longitude;
NSString *email;
//Sending Post Method, with parameter JSON (You can change your method of sending data to server just by replacing POST with GET)
[manager POST:[NSString stringWithFormat:#"http://myphp.com/api/v1/profile?authorization_code=%#&gps_lat=%#&gps_lng=%#&email=%#",yourAuthorizationCode,latitude,longitude,email] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"JSON: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error at creating post: %#", error);
}];
Hope it helps, give me feedback!

Related

How to get response string from NSURLSessionTask

I am using AFNetwork 3.0 for HTTP get request.
I am even getting response. But i want to take response data as NSString.
Can someone please help me how to get response data as NSString
Here is my code,
AFHTTPSessionManager *operation = [AFHTTPSessionManager alloc];
[operation GET:controlURL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"JSON: %#", responseObject);
NSLog(#"success: %#", responseObject);
NSString *xmlString = [responseObject ];// i am facing problem here
If you want response data in your string then try this:
NSString *str = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"responseData: %#", str);

Unable to post JSON Using afnetworking in ios

I am getting this error while posting json to url :
Invalid top-level type in JSON write'
I am even sending perfect JSON using afnetworking post request code But it keeps giving me error.
My code :
NSString * serviceType = #"xyz";
NSString * remarks =#"project deadline is near ";
NSString * emailId = #"xyx.live.com";
NSDictionary *params =
# {
#"serviceType" :serviceType,
#"remarks" :remarks,
#"emailId" :emailId
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
AFHTTPRequestOperationManager *manager2 = [AFHTTPRequestOperationManager manager];
AFJSONRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[serializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
manager2.requestSerializer = serializer;
[manager2 POST:#"http://xyx.com" parameters:jsonString success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON_post_fzzlogin: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//here is place for code executed in success case
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error while sending POST"
message:#"Sorry, try again."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
NSLog(#"Error: %#", error);
}];
Please help me out this regard .thanks in advance
You are trying to encode request twice because you set request serializer for AFHTTPRequestOperationManager and provide parameters as encoded JSON string. So you need to provide raw parameters if you want to use request serializer or don't use it and encode to JSON manually.
This is how you post JSON or rather NSDictionary by AFNetworking
NSDictionary *dict = #{#"Key":#"Value"};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[Util urlAppend:kListOfArticleCatagory] parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *responseObj = (NSDictionary *)responseObject;//casting to NSDictionary from id
NSLog(#"%#",responseObj);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Something went wrong :%#",operation.responseString);
}];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
}
You dont post JSON through AFNetworking, rather the NSDictionary as the parameters, it will get converted to JSON as you post it.

How to use AFNetworking to create JSON array

I am currently trying to create a JSON array like I do here like this:
NSURL *url = [NSURL URLWithString:currentJSON];
NSData *jsonData = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
if (jsonData) {
result = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&error];
}
Which works fine. Apart from I want it to time out if the internet connection is not great.
So I then wen to AFNetworking where I wrote code like this:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:currentJSON parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSError *error = nil;
result = [NSJSONSerialization JSONObjectWithData:responseObject
options:NSJSONReadingMutableContainers
error:&error];
[[NSUserDefaults standardUserDefaults] setObject:result forKey:#"All"];
[[NSUserDefaults standardUserDefaults] synchronize];
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
result = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"All"];
}
But this method always runs to a failure How come? What am I doing wrong?
Check that server is sending JSON using correct content type 'application/json'. AFNetowrking checks this out of the box and if receives something else (for example 'text/html'), failure block will be called.
Also AFNetworking does JSON to object parsing out of the box. 'id responseObject' is already the result of '[NSJSONSerialization JSONObjectWithData]'.
If you can't change content type sent by server, you could add that content type to accepted types using following snippet
NSMutableSet *accepted = [NSMutableSet set];
[accepted addObject:#"text/html"];
[accepted addObject:#"application/json"];
manager.responseSerializer.acceptableContentTypes = accepted;
Try this :
NSURL *url = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
result = (NSDictionary *)responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];

Differences between sending POST with AFNetworking and curl

I
ve been using AFNetworking 2 with success for some time, but I stumbled upon case where I don't know where to turn my head to. I have to make POST request in order to log in, send credentials alongside and receive JSON back with operation status. For some weird reason sending it via AFNetworking like this:
NSDictionary *params = #{#"login": self.loginField.text, #"password" : self.passField.text};
NSDictionary *data = #{#"data": params};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
//manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:server parameters:#{#"data" : params} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);
}];
I have to pack dictionary with parameters as a single "data" parameter. I do get back OK 200, but if I take a look in server logs I see that no data was transferred, which ended up as user not recognized.
But if send with curl this:
curl -d 'data={"login":"xx", "password":"yy"}' http://someurl/api/login/
I got perfectly fine response and in logs I see some actual data. Does anyone know how to deal with such a case?
If it helps, I'm doing it in iPhone simulator, not tested on actual device.
If you have a look at the AFNetworking source code, namely the class AFJSONRequestSerializer, you will see that the serialise function for that serialiser puts the parameters you hand over into the body - and not as an HTTP parameter as you expect.
You should use an AFHTTPRequestSerializer in your case - that will add the parameters as (URL-encoded) HTTP parameters to your URL.
Something like that should work in your case:
// build the JSON parameter string
NSDictionary *params = #{#"login": self.loginField.text, #"password" : self.passField.text};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
NSString *jsonString = [[NSString alloc] initWithBytes:[jsonData bytes]
length:[jsonData length]
encoding:NSUTF8StringEncoding];
// and now send the JSON parameter string as HTTP parameter
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
[manager POST:server
parameters:#{#"data" : jsonString}
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);
}];

Waiting for multipart image sending get completed

I'm impementing an application in iOS7, it's kind of a social network app with posts with images and a backend that saves all of the data sent form the client. The iOS client is sending the information of the post via json and after the info is sent, it starts to send the image via multipart form using AFNetworking.
I need to be notified when the image is sent, so that I can refresh the main view of the app with the new posts, including the recently posted by the client. In the practice if I request the backend for the last posts and the multipart hasn't finished, the sending of the image gets interruped and fails to send the image.
The backend is develop in WCF and is a RESTful JSON web service.
Here is the method that sends the post to the backend:
+(void)addPostToServerAddtext:(NSString *)text addimage:(UIImage *)image addbeach:(NSString *)beach location:(NSString*)location;
{
NSLog(#"entro a addPost");
NSString *urlBackend = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"URLBackend"];
NSData* dataImage = UIImageJPEGRepresentation(image, 1.0);
NSString* ImageName = [NSString stringWithFormat:#"%#_%#.jpg",idUser ,dateToServer];
NSString *jsonRequest = [NSString stringWithFormat:#"{\"Date\":\"%#\"...."];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#newPost",urlBackend]];
NSMutableURLRequest *request = [ [NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [NSData dataWithBytes:[jsonRequest UTF8String] length:[jsonRequest length]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:requestData];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
if (image != nil) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#FileUpload",urlBackend]
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:dataImage name:#"image" fileName:ImageName mimeType:#"image/jpg" ];
}
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
}
A couple of thoughts:
You say:
The iOS client is sending the information of the post via json and after the info is sent, it starts to send the image via multipart form using AFNetworking.
Technically, you're not waiting for the information to be sent, but you're doing these concurrently. Do you want these to be concurrent? Or sequential? Or why not just a single request that posts the information as well as the image?
I'd suggest using AFNetworking for both requests. You've got a powerful framework for managing network requests, and it feels awkward to see hairy NSURLConnection code in there.
If you keep the NSURLConnection code in there, note that you do not want to start a NSURLConnection, unless you used initWithRequest:delegate:startImmediately: with NO for that last parameter. You're effectively starting it twice, which can cause problems. I'd suggest removing the start call.
Setting all of that aside, what you want to do is to add a completion block parameter to your method, e.g., something like:
+ (void)addPostToServerAddtext:(NSString *)text addimage:(UIImage *)image addbeach:(NSString *)beach location:(NSString*)location completion:(void (^)(id responseObject, NSError *error))completion
{
// ...
if (image != nil) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#FileUpload",urlBackend] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:dataImage name:#"image" fileName:ImageName mimeType:#"image/jpg" ];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completion) completion(responseObject, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completion) completion(nil, error);
}];
}
}
You'd then invoke that like so:
[Persistence addPostToServerAddtext:text addimage:image addbeach:nil location:annotation completion:^(id responseObject, NSError *error) {
if (error) {
// handle error
return
}
// otherwise use the responseObject
}];
Now, I don't know what parameters you want to return in your completion block (I'm assuming you wanted to return what the AFHTTPRequestOperationManager did), but just change the parameters for that completion block as suits your needs.
Unrelated to your original question, but I notice that you're building jsonRequest like so:
NSString *jsonRequest = [NSString stringWithFormat:#"{\"Date\":\"%#\"...."];
That's a little risky if any of those fields include user supplied information (e.g. what if the user used double quotes in the information provided). I'd suggest you build a dictionary, and then build the jsonRequest from that. It will be more robust. Thus:
NSDictionary *dictionary = #{#"Date" : date,
#"Message" : message};
NSError *error = nil;
NSData *request = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
if (error)
NSLog(#"%s: dataWithJSONObject error: %#", __FUNCTION__, error);
Or, if you use AFNetworking, I believe it will do this JSON conversion of your dictionary for you. But, bottom line, be very wary about creating JSON strings yourself, at least if the request might include any user supplied information.

Resources