I am trying to construct a POST request with certain parameters in the body of the message but am struggling with handling / seeing the response.
This is the request I am trying to recreate in Obj C:
I am somewhat familiar with the code to create this request but am struggling with parsing the response into meaningful data. This is what my method currently looks like for this (it appears to be Successful):
NSLog(#"WEB SERVICE CALLED!");
NSURL *aUrl = [NSURL URLWithString:#"xxx"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
NSString *postString = #"grant_type=password&username=xxx&password=xxx";
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection= [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if(connection) {
NSLog(#"Connection Successful");
} else {
NSLog(#"Connection could not be made");
}
}
How can I see what my response is? Thanks in advance for any help!
UPDATE
I added this bit and can see that my response gives me a code 200 (success) but the data object looks like it needs to be serialized as it looks like a hex string. This is what I am doing to handle the response / data / error:
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// your data or an error will be ready here
NSLog(#"RESPONSE: %#",response);
NSLog(#"DATA: %#",data);
NSLog(#"ERROR: %#",error);
}];
This is what the log for the data object looks like:
NSError *error;
id obj= [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!obj) {
NSLog(#"JSON parse error: %#", error);
} else {
NSLog(#"obj= %#", obj);
}
Related
//Below is the code i have used to perform simple httpPOST. But app hangs on App launch on splash screen and crashes . i am doing an API Call on applaunch in Appdelegate
- (NSDictionary *)postUserRegWithUrl:(NSString *)urlString andParams:(NSString *)paramString{
NSString * encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)paramString,
NULL,
(CFStringRef)#"+",
kCFStringEncodingUTF8 ));
NSDictionary *responseDictionary;
NSError *err;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",kBaseProdURL,urlString]]];
NSData *data = [encodedString dataUsingEncoding:NSUTF8StringEncoding];
[request setTimeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:data];
NSLog(#"the data Details is =%#", request);
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *resSrt = [[NSString alloc]initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(#"got response==%#", resSrt);
if(resSrt.length)
{
responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&err];
NSLog(#"Response dictionary formed is =%#", responseDictionary);
} else {
NSLog(#"failed to connect");
[self showAlertViewTitle:#"Please try later" withMessage:#"Something went wrong"];
}
return responseDictionary;
}
You shouldn't execute your network calls synchronously, especially on main thread. Either use sendAsynchronousRequest or just use any good networking library, like AFNetworking, which do this out of the box.
First set the timeoutInterval for your request. if your request takes more time then you have to stop the api call and inform the user with proper error message.
For example:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1200.0];
Don't use Synchronised Request. It will block your main thread.
If your network is slow or server is not responding then your app will take more time to load. Which is not good for the user experience.
Remember, your app’s load time is your first chance to impress your users.
Use Asynchronised Request of the NSURLConnection. Handle the response in the api completion block.
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSString *resSrt = [[NSString alloc]initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"got response==%#", resSrt);
if(resSrt.length)
{
responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&err];
NSLog(#"Response dictionary formed is =%#", responseDictionary);
} else {
NSLog(#"failed to connect");
}
}];
Change queue:[NSOperationQueue mainQueue] parameter based on your need.
queue -> An NSOperationQueue upon which the handler block will
be dispatched.
Using uber rush API I've successfully created authorization token. But when I try to create quote all I get is HTML page. I am making http request from iOS Objective C. This is how I am making http request:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/v1/deliveries/quote", kLiveURL]]];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"Bearer %#", [[NSUserDefaults standardUserDefaults] objectForKey:kUberRushAccessTokenKey]] forHTTPHeaderField:#"Authorization"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%lul", (unsigned long)[jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:jsonData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (data) {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (error) {
NSLog(#"dataString: %#",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
} else {
NSLog(#"jsonResponse: %#", jsonResponse);
}
} else {
NSLog(#"httpResponse: %#", response);
}
}];
Thanks for help in advance :)
I am trying to parse XML data. I did not use XMLParser. I used this below code and somehow it worked. I parsed XML as JSON and I was getting response in dictionary format. Below is my code -
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *jsonError;
if (error == nil){
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(#"Error : %#",error);
failureBlock(#{#"ErrorCode": [NSString stringWithFormat: #"%ld", (long)jsonError.code],
#"ErrorText": jsonError.localizedDescription});
} else {
NSLog(#"success : %#",jsonResponse);
successBlock(jsonResponse);
}
}else{
failureBlock(#{#"ErrorCode": [NSString stringWithFormat: #"%ld", (long)error.code],
#"ErrorText": error.localizedDescription});
}
}] resume];
Though this was working but all of a sudden I started getting error message like -
ErrorCode = 3840;
ErrorText = "The data couldn\U2019t be read because it isn\U2019t in the correct format.";
Then how it was working earlier? Can someone please guide me, how I can use correct XML Parsing. Also the xml url if first redirecting to a login page which is being bypassed in the above code and we get the XML response directly. In the app we have a UIWebView container for login and we get cookies. Those cookies are applied on every service call. In above code, when it was working, it was bypassing the login page and returning the response in json format. I also tried this below code -
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithData:data];
[xmlparser setDelegate:self];
[xmlparser parse];
}] resume];
And then wrote didStartElement, foundCharacters and didEndElement. But it is trying to parse the login page itself. Login page is not bypassed if I use NSXMLParser.
Please help, any suggestion is most welcome.
You can also use this link form XML parsing: https://github.com/nicklockwood/XMLDictionary
And Also try this code :
NSString *baseUrl = [NSString stringWithFormat:#"your string"];
NSURL * url = [NSURL URLWithString:baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"GET"];
[request setHTTPShouldHandleCookies:NO];
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
failure(error);
} else if(response)
{
NSDictionary * jsonDic =[NSDictionary dictionaryWithXMLData:data];
NSLog(#"Response print Hear%#",jsonDic);
}
}];
Undoubtedly, people will shake their head in shame at the following, but I would appreciate the help.
I seem to make the same calls to NSURLSessionUploadTask with pretty much the same structure throughout the program. Hence, I am trying to make it a method which I can call from anywhere in the program and, when it's complete, return the NSDictionary to the call which made it.
Currently I have the following:
-(NSDictionary *)serverRequest:(NSString *)requestURL withDictionary:(NSDictionary *)sendDict {
NSURL *homeURL = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/%#",baseURL, requestURL]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:homeURL];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setCachePolicy:NSURLCacheStorageAllowedInMemoryOnly];
NSData *sentData = [NSJSONSerialization dataWithJSONObject:sendDict options:0 error:nil];
NSURLSessionUploadTask *uploadTask = [_session uploadTaskWithRequest:request fromData:sentData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
returnedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if ([returnedData[#"code"] isEqualToString:#"OK"])
{
dispatch_async(dispatch_get_main_queue(), ^{
return returnedData;
});
}
}];
[uploadTask resume];
}
So I pass in the URL I want to call, and the NSDictionary which is then sent to the server. The server replies, with a JSON response, which I then turn into returnedData. I simply wish to pass this data back to the call which made it ... something like:
NSDictionary *mydata = #{#"email": userRegisterTextFieldEmailAddress.text};
NSDictionary *passedBackData = [self serverRequest:#"checkUserName" withDictionary:mydata];
When I try this it won't build as the dispatch_async isn't the right format etc, etc. I have tried to read up on this, and can't believe it's a hard problem? Surely others aren't making the same call with the same code each time they want to return some data from a web server?
Thanks in advance for any help you can give in clearing up my misunderstanding.
What you'd generally do is add a completion block parameter to your method, that specifies what you want to do upon receiving the response. So, add a block parameter to your method and add the code that calls that block, something like:
- (void) serverRequest:(NSString *)requestURL withDictionary:(NSDictionary *)sendDict completion:(void (^)(id responseObject, NSError *error))completion
{
NSURL *homeURL = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/%#", baseURL, requestURL]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:homeURL];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setCachePolicy:NSURLCacheStorageAllowedInMemoryOnly];
NSData *sentData = [NSJSONSerialization dataWithJSONObject:sendDict options:0 error:nil];
NSURLSessionUploadTask *uploadTask = [_session uploadTaskWithRequest:request fromData:sentData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// report any network-related errors
if (!data) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(nil, error);
});
}
return;
}
// report any errors parsing the JSON
NSError *parseError = nil;
returnedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (!returnedData) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(nil, parseError);
});
}
return;
}
// if everything is ok, then just return the JSON object
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(returnedData, nil);
});
}
}];
[uploadTask resume];
}
You'd then call this serverRequest method, specifying precisely what you want to do with the data you receive:
[self serverRequest:url withDictionary:dictionary completion:^(id responseObject, NSError *error) {
if (responseObject) {
// do what you want with the response object here
} else {
NSLog(#"%s: serverRequest error: %#", __FUNCTION__, error);
}
}];
Clearly, you can change this as you see fit, but hopefully this illustrates the idea. If, for example, you knew that responseObject was always going to be a NSDictionary, then I'd change the references to id responseObject with NSDictionary *responseObject.
But the idea is that you should just provide a block that takes the response data and/or the error as parameters. That way, the code that calls this method can specify what should happen when the asynchronous network request completes.
So the call is asynch so you can't really do it like that. What I tend to do is wait for the method to return on its own and then get the main thread (as you've done) and then update UI/models etc like that.
I am making a synchronous call to the web service and sometimes I get the correct result back from the web service and sometimes I get HTML result indicating a Runtime error. Is there anything on the iOS side I have to do to correctly call the web service. Here is my code:
NSURLResponse *response = nil;
NSError *error = nil;
NSString *requestString = #"some parameters!";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[requestString dataUsingEncoding:NSUTF8StringEncoding]];
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
NSString *responseData = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
Is it because I am not releasing properly?
you have to set the delegate methods of urlconnection like this
NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
urLConnection=[[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
and the following delegate methods do the trick
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
[receivedData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
you will receive error in the following delegate if connection fails
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{}
you better get the response from the finished connection which tells that all the data been received
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
recievedData //the complete data
}
try this
NSError * error;
NSURLResponse * urlresponse;
NSURL * posturl=[NSURL URLWithString:#"Type your webService URL here"];
NSMutableURLRequest * request=[[NSMutableURLRequest alloc]initWithURL:posturl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:50];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSString * body=[NSString stringWithFormat:#"fbid=%#",userid];
[request setHTTPBody:[body dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
NSData * data=[NSURLConnection sendSynchronousRequest:request returningResponse:&urlresponse error:&error];
if (data==nil) {
return;
}
id jsonResponse=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSLog(#" json response %#", jsonResponse);
if (![[jsonResponse objectForKey:#"code"] isEqualToNumber:[NSNumber numberWithInt:200]]) {
NSLog( #" successFull ");
this method works for me for more information read facebook documents for ios login
//set request
NSURLRequest *req=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://indianbloodbank.com/api/donors/?bloodgroup=O%2B"]];
NSLog(#"Request-%#",req);
NSError *err=nil;
NSURLResponse *res=nil;
NSData *xmldata=[NSURLConnection sendSynchronousRequest:req returningResponse:&res error:&err];
NSLog(#"Error-%#",err);
NSLog(#"Response-%#",res);
NSLog(#"XmlData-%#",xmldata);
xmldictionary=[XMLReader dictionaryForXMLData:xmldata error:&err];
NSLog(#"XmlDictionary-%#",xmldictionary);
mArray=[xmldictionary retrieveForPath:#"response.donorslist.donors"];
NSLog(#"MutableArray-%#",mArray);
lblname.text=[[mArray objectAtIndex:0]valueForKey:#"name"];
lbllocation.text=[[mArray objectAtIndex:0]valueForKey:#"location"];
lblphone.text=[[mArray objectAtIndex:0]valueForKey:#"phone"];
NSLog(#"%#,%#,%#",lblname.text,lbllocation.text,lblphone.text);
NSLog(#"%#",mArray);
For loop:
for (int i=0; i<mArray.count; i++)
{
Data * don=[NSEntityDescription insertNewObjectForEntityForName:#"Data" inManagedObjectContext:app.managedObjectContext];
don.donorid=[[mArray objectAtIndex:i]valueForKey:#"id"];
don.gender=[[mArray objectAtIndex:i]valueForKey:#"gender"];
don.name=[[mArray objectAtIndex:i]valueForKey:#"name"];
don.location=[[mArray objectAtIndex:i]valueForKey:#"location"];
don.phone=[[mArray objectAtIndex:i]valueForKey:#"phone"];
[app saveContext];
NSLog(#"%#,%#,%#,%#,%#",[[mArray objectAtIndex:i]valueForKey:#"id"],[[mArray objectAtIndex:i]valueForKey:#"gender"],[[mArray objectAtIndex:i]valueForKey:#"name"],[[mArray objectAtIndex:i]valueForKey:#"location"],[[mArray objectAtIndex:i]valueForKey:#"phone"]);
}