I'm trying to use an AFHTTPRequestOperation (via an AFHTTPRequestOperationManager) to transmit some information (say, "foo = bar") to an backend expecting JSON, using a setup like this:
- (void) postTest {
NSString *completePath = #"https://httpbin.org/post";
NSDictionary *dataToJSONfy = #{#"foo":#"bar"};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject: dataToJSONfy options:kNilOptions error:&error];
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:#"POST" URLString:completePath parameters:nil];
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
AFHTTPRequestOperation *operation =
[self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id JSON) {
NSLog(#"... success! %#", JSON);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"... failure! Error: %#", error);
}];
[self.operationQueue addOperation:operation];
}
Which shows up like this
{
args = {
};
data = "{\"foo\":\"bar\"}";
files = {
};
form = {
};
headers = {
[...]
};
json = {
foo = bar;
};
origin = [...];
url = "http://httpbin.org/post";
}
Question: what would I need to change in order to include my information ("foo = bar;") in the 'form =' section of the body rather than the 'json =' bit?
I want to include valid JSON (e.g. some server response stored earlier) in the post, but as per API specification, everything's supposed to be located under the 'form = {};' part. So I guess I want JSON as formdata.
NSData *jsonData = [NSJSONSerialization dataWithJSONObject: dataToJSONfy options:kNilOptions error:&error];
//new!
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *bodyString = [NSString stringWithFormat:#"{'Form': '%#'}, jsonString]; //! not 100% what you want. I stick with valid JSON here
NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:#"POST" URLString:completePath parameters:nil];
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:bodyData]; //!
first you need to declare nsdictionary block just after the postTest method like
__block NSDictionary *dict=[NSDictionary alloc] init];
and in success block you should use
dict=[NSJSONSerlization JSONObjectWithData:JSON options:NSJSONReadingAllowFragments error:nil];
NSLog(#"... success! %#", dict);
Related
I am trying to upload a UIImage to .Net server by converting the image into base 64 and NSData. But I am getting the response null. Here is my code.
NSString *base64Encoded = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSString *post= [NSString stringWithFormat:#"myServerSideUrl?Image=%#",base64Encoded];
NSLog(#"PostData: %#",post);
NSString* webStringURL = [post stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
NSURL* url = [NSURL URLWithString:webStringURL];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSError *error;
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSData *responseData = [[NSData alloc]initWithData:urlData];
if ([response statusCode] >=200 )
{
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData: responseData options:0 error:nil];
NSLog(#"%#",jsonData);
}
After some time, I just checked in postman showing like url too long HttpResponseCode:414. Also I tried to send the image in NSData format using AFNetwork, getting the same response. And I just googled about this, saying like send the base 64 string in body. When I tried to send image in body, server side can't get the image. They are creating the API like GET method but the actual method is POST. Is there any other solution about this. Any suggestions.
You are setting NSData to your request body without defining any key-value pair.
Try this code using AFNetworking...
- (void) uploadFileRequestWithHttpHeaders:(NSMutableDictionary*) headers
withServiceName:(NSString*) serviceName
withParameters:(NSMutableDictionary*) params
withFileData:(NSArray*) files
{
NSString *serviceUrl = [httpBaseURL stringByAppendingPathComponent:serviceName];
if (headers == nil)
{
NSDictionary *headers = [[NSDictionary alloc] initWithObjectsAndKeys:#"multipart/form-data",#"Content-Type",nil];
[self setHeaders:headers];
}
else
{
[headers setObject:#"multipart/form-data" forKey:#"Content-Type"];
[self setHeaders:headers];
}
[httpSessionManager POST:serviceUrl
parameters:params
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
for (NSData *fileData in files)
{
[formData appendPartWithFileData:fileData name:#"userProfileImg" fileName:#"profile_pic.jpg" mimeType:#"image/jpeg"];
}
}
success:^(NSURLSessionDataTask *task, id responseObject) {
if (success != nil)
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
if (failure != nil)
}];
}
- (void) setHeaders:(NSDictionary*) headers
{
if (headers != nil)
{
NSArray *allHeaders = [headers allKeys];
for (NSString *key in allHeaders)
{
[httpSessionManager.requestSerializer setValue:[headers objectForKey:key] forHTTPHeaderField:key];
}
}
}
- (void) addQueryStringWithParams:(NSDictionary*) params
{
[httpSessionManager.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) {
__block NSMutableString *query = [NSMutableString stringWithString:#""];
NSError *err;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&err];
NSMutableString *jsonString = [[NSMutableString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
query = jsonString;
return query;
}];
}
And call this method like this..
NSArray *objects = [NSArray arrayWithObjects:#"multipart/form-data",#"1.0",#"ios",token, nil];
NSArray *Keys = [NSArray arrayWithObjects:#"content-type",#"version",#"os",#"token", nil];
NSMutableDictionary *headers = [[NSMutableDictionary alloc]initWithObjects:objects forKeys:Keys];
NSMutableDictionary *paraDic = [[NSMutableDictionary alloc] init];
[paraDic setObject:self.userNameField.text forKey:#"name"];
NSData * userProfileImg = UIImageJPEGRepresentation(image, 0.8f);
imageDataArray = [NSArray arrayWithObjects:userProfileImg, nil];
[self uploadFileRequestWithHttpHeaders:headers withServiceName:#"updateProfile" withParameters:params withFileData:files];
You can try this code using NSURLSession-
- (void)postRequestForSubmitDataToServer {
//Put your action URL
NSURL *aUrl = [NSURL URLWithString:#"action_url.php?&attachment=att&submit=submit"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil) {
//change JSON type according to ur need.
NSArray *JSON = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: &error];
NSLog(#"Data = %#",JSON);
} else {
NSLog(#"%#", error);
}
}];
[postDataTask resume];
}
My form data-
<form action="action_url.php" method="post" enctype="multipart/form-data">
Your Photo: <input type="file" name="attachment" size="25" /><br>
<input type="submit" name="submit" value="Submit" /> </form>
I'm currently working with YouTube API and allowing users to subscribe to other channels, however now I'm supposed to send a POST method that includes a "Request Body".
Here's the Request that's I'm supposed to send :
POST https://www.googleapis.com/youtube/v3/subscriptions?part=snippet&key={YOUR_API_KEY}
//The Request Body
{
"snippet": {
"resourceId": {
"channelId": "UCJZ7f6NQzGKZnFXzFW9y9UQ"
}
}
}
Here's my current code
+(void)subscribeToChannel:(NSString *)channelID {
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName clientID:clientIDclientSecret:clientSecret];
NSString *urlStr;
NSMutableURLRequest *request;
urlStr = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/subscriptions?id=%#&key=mykey", channelID];
[request setHTTPBody:[#"{ \"snippet\": { \"resourceId\": { \"channelId\": \"UCJZ7f6NQzGKZnFXzFW9y9UQ\" } } }" dataUsingEncoding:NSUTF8StringEncoding]];
NSURL *url = [NSURL URLWithString:urlStr];
request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[auth authorizeRequest:request
completionHandler:^(NSError *error) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
NSString *output = nil;
if (error) {
output = [error description];
NSLog(#"ERRO LOADING INFO : %#", output);
} else {
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:nil];
if (data) {
output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
} else {
output = [error description];
}
}
});
}];
}
I'm positive that I'm doing something wrong in [request setHTTPBody] but that's the only thing that I could think about.
You're attempting to set the NSMutableURLRequest's HTTPBody before you have allocated an instance of NSMutableURLRequest.
NSString *urlStr;
// The request is nil
NSMutableURLRequest *request;
urlStr = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/subscriptions?id=%#&key=mykey", channelID];
// At this point the request is still nil so you are attempting to set the HTTPBody on a nil object
[request setHTTPBody:[#"{ \"snippet\": { \"resourceId\": { \"channelId\": \"UCJZ7f6NQzGKZnFXzFW9y9UQ\" } } }" dataUsingEncoding:NSUTF8StringEncoding]]
You also mentioned in a comment that you are receiving a "This API does not support parsing form-encoded input." error. You may be receiving this error because you are not setting the content-type (I came to this conclusion from googling the error. I may be wrong).
This should work:
NSString * urlStr = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/subscriptions?id=%#&key=mykey", channelID];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
// Set the content type
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
// Create the dictionary that you will be using in the HTTPBody
NSDictionary * httpBody = #{
#"snippet": #{
#"resourceId": #{
#"channelId": channelID
}
}
};
// Make sure that the above dictionary can be converted to JSON data
if([NSJSONSerialization isValidJSONObject:httpBody])
{
// Convert the JSON object to NSData
NSData * httpBodyData = [NSJSONSerialization dataWithJSONObject:httpBody options:0 error:nil];
// set the http body
[request setHTTPBody:httpBodyData];
}
I do this when bumping places using the Google Places API, but it should work the same.
Try this:-
NSMutableDictionary *channelId = [[NSMutableDictionary alloc]init];
[channelId setObject:#"UCJZ7f6NQzGKZnFXzFW9y9UQ" forKey:#"channelId"];
NSMutableDictionary *resourceId = [[NSMutableDictionary alloc]init];
[resourceId setObject:channelId forKey:#"resourceId"];
NSDictionary * postDictionary = [NSDictionary dictionaryWithObject:resourceId forKey:#"snippet"];
NSError * error = nil;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:postDictionary options:NSJSONWritingPrettyPrinted error:&error];
[request setHTTPBody:jsonData];
Posted a query previously about JSON parsing not working properly. Did more looking into it with a packet sniffer and also with another client that works properly and found out it's a syntax thing, that I still can't seem to solve.
The code in the bottom makes the HTTP request to have the JSON in it as:
{"key":"value"}
And my server is actually looking for a JSON in the following syntax:
key=%22value%22
I tried to write some code that does this manually, but figured there must be something out of the box for iOS, and I don't want to have faults in the future.
I messed around with it for a while trying to find the right code for the job, but couldn't (you can see some code I tried commented out). Can anyone help me?
+ (NSString*)makePostCall:(NSString*)urlSuffix
keys:(NSArray*)keys
objects:(NSArray*)objects{
NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
// NSString *dataString = [self getDataStringFromDictionary:params];
// NSData *jsonData = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
// id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
// NSLog(#"%#", jsonObject);
if (!jsonData) {
// should not happen
NSError *error;
NSLog(#"Got an error parsing the parameters: %#", error);
return nil;
} else {
// NSString *jsonRequest = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// NSLog(#"%#", jsonRequest);
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", urlPrefix, urlSuffix]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
// NSData *requestData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
// [request setValue:#"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody: jsonData];
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
// TODO: handle error somehow
NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return returnString;
}
}
I have used SBJsonParser and ASIFormDataRequest for Posting and JSON Parsing, like
NSString *urlStr = #"http:facebookpage/second/index.php";
NSURL *log_Url = [NSURL URLWithString:urlStr];
request = [ASIFormDataRequest requestWithURL:log_Url];
[ASIHTTPRequest setSessionCookies:nil];
[request setPostValue:uName.text forKey:#"uname"];
[request setPostValue:passWord.text forKey:#"pwd"];
[request setPostValue:#"login" forKey:#"req"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
response = [request responseString];
}
NSLog(#"%#",response);
Then For Parsing:
parser = [[SBJsonParser alloc]init ];
json_dic_values = [parser objectWithString:response error:nil];
NSString *status = [json_dic_values objectForKey:#"status"];
Url_pathforPages = [json_dic_values objectForKey:#"url"];
NSString *sessionID = [json_dic_values objectForKey:#"session_id"];
Here I need to know how can i do this same in NSJsonSerialization.
Everything is working fine in above method....
There are really only a few methods in NSJSONSerialization. Take a look at the documentation.
json_dic_values = [NSJSONSerialization JSONObjectWithData: [response dataUsingEncoding: NSUTF8StringEncoding] options: 0 error: &error];
I am using a method to call the Web Services and Upload the Transcription Audio File On the Server. The method is as follows:
- (NSDictionary *)UploadTranscriptionAudio:(NSString *)uploadfor forPN_ID:(NSString
*)pn_id forTaskFlag:(NSString *)taskflag documentPath:(NSString *)documentpath
forUserName:(NSString *)username file_path_msd:(NSString *)file_path_msd
audioFilePath:(NSString *)audiofilepath{
NSDictionary *response = nil;
NSURL * url = [NSURL URLWithString:[AppDelegate sharedInstance].str_webServiceUrl];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:uploadfor forKey:#"Uploadfor"];
[request setPostValue:pn_id forKey:#"PNID"];
[request setPostValue:taskflag forKey:#"task_flag"];
[request setPostValue:documentpath forKey:#"Path"];
[request setPostValue:username forKey:#"Username"];
[request setPostValue:file_path_msd forKey:#"file_path_msd"];
[request setFile:audiofilepath forKey:#"uploadedfile"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
response = (NSDictionary*)[request responseString];
NSLog(#"Response = %#",response);
return response;
}
return response;
}
This method is still returning me a NSstring in response. What i want is that this method should return me a NSDictionary. As I have to use the value for the keys inside that dictionary somewhere else. Can somebody help me on this.
hello shikher maddy says right n u can parse string as follow
if (responseString == NULL) {
// do something u want
} else {
NSDictionary *jsonResponse = [responseString JSONValue];
NSLog(#" %#",jsonResponse);
}
If I were you I would use SBJSONParser like this:
SBJsonParser *parser= [[SBJsonParser alloc] init];
NSDictionary *dictionnary = [parser objectWithString:responseString error:nil];