I have successfully used JSON as arguments to a POST webservices in my apps by making the data representation of the JSON the HTTP body:
//Prep
NSData *requestData = [NSJSONSerialization dataWithJSONObject:<my JSON> options:0 error:nil];
NSString *apiString = <the webservice>;
//POST
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiString]];
[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];
//Go
NSURLResponse *response = nil;
queryResultData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Which works great.
The trouble is, this works for a webservice which is expecting a single JSON argument as the http body.
How can I include JSON as one of many arguments, the way you can use the data encoding of #"arg1=val1&arg2=val2".
For example: image you have a webservice expecting something like
http://mysite.com/api/v1/route/test?data={json:%22true%22}&other=abcdefg
Which must be submitted as a POST.
This, interestingly, has a JSON dictionary as only one argument of many, and not in the body at that. I can't figure out how to add these arguments to the post.
EDIT
Here's the same concept in php. How do you do this in Cocoa?
$data = array('x' => 1, 'name => 'fred');
$json = json_encode($data);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, array('json_data' => $json));
-- or --
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, 'something=whatever&json_data='.$json);
Related
I have a WCF web-service. If I just put the URL into the browser, I will get the error message: Forbidden. But if I post data through Fetcher(a HTTP Simulator in OS X), I can get the correct return value.
Now, I tried to use NSURLConnection to post data to the web-service and fetch the return value.
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:postURL];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLResponse * response = nil;
NSError * error = [[NSError alloc] init];
receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString * receivedStr = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
But all I get is just the html code of the error page I can see from the browser(that forbidden message).
Please help me figure it out. Thanks in advance.
EDIT:
I set up a PHP server and try to do the same thing. I works perfectly. Therefore, I highly doubt it is the WCF problem. Anyone has some good ideas?
if you use generated .svc service you need to :
change
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
to
[request addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-type"];
also you need to SOAPAction field according to operation you request
What is you postData?
I am calling a web service in iOS. For this, I need to set the header in NSMutableURLRequest object. My service takes two string parameters and returns data in JSON format.
What are the the fields that I need to set in the header (Both while using GET and POST) using the setValue:forHTTPHeaderField:.
We do not need to use setHTTPBody: while using GET.. right???
I had the same question and I resolved (using some code from Iducool and Ankit Mehta) like this...
NSURL *theURL = [NSURL URLWithString:#"yourURL"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20.0f];
//Specify method of request(Get or Post)
[theRequest setHTTPMethod:#"GET"];
//Pass some default parameter(like content-type etc.)
[theRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
//Now pass your own parameter
[theRequest setValue:yourValue forHTTPHeaderField:theNameOfThePropertyValue];
NSURLResponse *theResponse = NULL;
NSError *theError = NULL;
NSData *theResponseData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
//Now you can create a NSDictionary with NSJSONSerialization
NSDictionary *dataDictionaryResponse = [NSJSONSerialization JSONObjectWithData:theResponseData options:0 error:&theError];
NSLog(#"url to send request= %#",theURL);
NSLog(#"%#",dataDictionaryResponse);
Look at this code which i am using to call a web service and thats working for me
+(NSString *)http_post_method_changed:(NSString *)url content:(NSString *)jsonContent{
NSURL *theURL = [NSURL URLWithString:url];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20.0f];
NSData *requestData = [jsonContent dataUsingEncoding:NSUTF8StringEncoding];
[theRequest setHTTPMethod:#"POST"];
[theRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[theRequest setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPBody: requestData];
NSURLResponse *theResponse = NULL;
NSError *theError = NULL;
NSData *theResponseData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
NSString *data=[[NSString alloc]initWithData:theResponseData encoding:NSUTF8StringEncoding];
NSLog(#"url to send request= %#",url);
NSLog(#"response1111:-%#",data);
return data;
}
Both while using GET and POST We do not need to use setHTTPBody?
setHTTPBody only make sense when you are using POST request. GET don't need it.
For Header parameters do something like below
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20.0f];
//Specify method of request(Get or Post)
[theRequest setHTTPMethod:#"GET"];
//Pass some default parameter(like content-type etc.)
[theRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
//Now pass your own parameter
[theRequest setValue:yourObj forHTTPHeaderField:#"your parameter name"];
setHTTPBody is used when HTTP method POST is being used.
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:theUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120.0];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:data];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
Here the data is nothing but NSData of JSON data that need's to be sent.
I'm trying to use NSURLConnection sendSynchronousRequest: to send a binary file (an JPEG image) to a server. The code I have is:
// url contains the URL of the remote server.
// fileURL contains the URL for the local file to be sent.
request = [NSMutableURLRequest requestWithURL:url];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPMethod:#"PUT"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"image/jpeg" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBodyStream:[NSInputStream inputStreamWithURL:fileURL]];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
if (requestError != nil) {
NSLog(#"%#", requestError);
return NO;
}
This almost works. The remote server receives the request properly, and responds with an appropriate JSON object. But sendSynchronousRequest: blocks until the timeout value, and then reports a timeout.
Elsewhere, I'm able to send and receive JSON objects properly using pretty much this same code pattern, so I'm baffled why this one would be timing out.
in iOS to create this
"{
"email":string,
"password":string
}"
json request body, i am passing the nsdata that i create from the string
email=myname#domain.com&password=mypassword
to the setHTTPBody method of the NSMutableURLRequest.This works fine im ok with this.
But what if i want to create this
"{
"post":
{
"title":string,
"room_id":int,
"content":string,
}
}"
json request body? i tried to make some string combinations to solve this recursion but didnt work out really. I also checked the methods of NSMutableURLRequest but i couldnt find something related to solve this.
edit:
This creates the post as it should be its fine, but i need an equivalent to the string email=myname#domain.com&password=mypassword for the recursive case. When i send the data as it should be it does not work. When i send as the string that i provided it works.
NSString *usertoken = [appDelegate token];
NSString *posttopic = #"111testtopic";
NSString *postbody = #"111testbody";
NSDictionary *dict = #{#"post":#{#"title":posttopic,#"room_id":#"246",#"content":postbody}};
NSData *body = [NSJSONSerialization dataWithJSONObject:dict
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *postLength = [NSString stringWithFormat:#"%d", [body length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
//send the post
NSString *urlstring = [NSString stringWithFormat:#"http://mydomain.com/posts.json?auth_token=%#", usertoken];
[request setURL:[NSURL URLWithString:urlstring]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:body];
NSURLResponse *response;
NSData *POSTReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
Try this
NSDictionary *dict = #{#"post":#{#"title":string,#"room_id":int,#"content":string}};
NSData *body = [NSJSONSerialization dataWithJSONObject:dict
options:NSJSONWritingPrettyPrinted
error:&error];
the idea is to use some nested dictionaries to describe your json and serialize them to get your jsonData to pass to the request.
I am trying to POST JSON data to my asp.net MVC server from an iPhone app. The method in my server looks like this:
[HttpPost]
public String MyMethod(Stream anUpload) { ... }
And here is the code to POST the JSON from my app:
NSString *theURL = [NSString stringWithFormat:#"http://192.168.1.103/MyServer/MyMethod"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:theURL]];
[theRequest setHTTPMethod:#"POST"];
// Serialize my data.
NSData *theData = [NSJSONSerialization dataWithJSONObject:theList options:kNilOptions error:nil];
[theRequest setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[theRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[theRequest setValue:[NSString stringWithFormat:#"%d", [theData length]] forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPBody:theData];
However, when I send the request, I just get an error message from the server, the MyMethod() never gets called. I am assuming that there is an issue with ASP accepting the POST data. Any ideas?
EDIT: Answer below
I found the answer:
I just needed to change the server-side function to
public String MyMethod(List<string> aList) { ... }
The ModelBinder was trying to deserialize the JSON for me, and it didn't like my parameter being a Stream.