Hi I am very new for Ios in my project I am integrating web services ok that's fine.
Here when I send proper request to the server, the response is coming from server like below "my first Response".
And if we send the wrong request to the server then response is coming from server like below "my second Response."
So we don't know which type of Json object we get from server after send request.
Here my main requirement is If we get proper response(like below first response) from server then we can save all elements which we want.
And if we get wrong response (like below second response) then how can we find and how to print that message because some times we get proper response and some times we get wrong response from server so how can we find and how can we save that response.
Please help me.
If send proper request then Response:-
responseObject = {
{
Name = Broad;
DeptNo = A00;
BatchNo = 23;
DeptId = 120;
},
{
Name = James;
DeptNo = B00;
BatchNo = 23;
DeptId = 123;
},
}
If we send wrong request then Response:-
responseObject = {
error = 1;
message = "Invalid Code";
}
my code:-
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
#"12345678" ,#"scacode",
nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"my url"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:15.0];
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"POST"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
if (error) {
NSLog(#"dataTaskWithRequest error: %#", error);
}
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200) {
NSLog(#"Expected responseCode == 200; received %ld", (long)statusCode);
}
}
NSError *parseError;
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (!responseObject) {
NSLog(#"JSON parse error: %#", parseError);
} else {
NSLog(#"responseObject = %#", responseObject);
}
}];
[task resume];
}
In your case you can use as following:
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if([responseObject objectForKey:#"error"] == nil)
{
//You are getting correct response
}
else{
// You are getting response with error
}
You can check response has a key with error. Otherwise you can use new variable in server side for all responses like statusCode. So if you get error or success, your server side can be set it to statusCode. It's very clear way for doing this.
You can use UIAlertView to display the error messages
if([responseObject objectForKey:#"error"] == nil)
{
//You are getting correct response
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert" message:#"Your Message" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
else
{
// You are getting response with error
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert" message:#"Error Message" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
I'm guessing you haven't posted whole responseObject(when sending proper request). Assuming that you're getting error=0 key when response is proper, you can do this:
NSMutableDictionary *jsonDictionary= [NSMutableDictionary alloc]init]
jsonDictionary=responseObject;
if([jsonDictionary valueForKey:#"error"]==#"0"]
{
//do some stuff
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Invalid Request" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
Related
I want to pass a JSON dictionary as a parameter by using uploadUrl, but it gives me an Unsupported Url error with code-1002.
When I hit this URL on Postman, it works perfectly. How do I implement this using a JSON model?
NSString *uploadUrl =#"<Your host URL>";
[JSONHTTPClient postJSONFromURLWithString:uploadUrl params:nil
completion:^(NSDictionary *json, JSONModelError *err)
{
if(err == nil)
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"success" message:#"uploaded" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
completionHanldler(json);
}
else
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Failed" message:#"uploaded" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
NSMutableDictionary *errorDict=[[NSMutableDictionary alloc]init];
if(err.code==-1009)
[errorDict setObject:#"The Internet connection appears to be offline."forKey:#"error"];
else
[errorDict setObject:#"Error occurred. Please try again!"forKey:#"error"];
completionHanldler(errorDict);
}
}];
stringByAddingPercentEscapesUsingEncoding
This method solved this issue. Previously I was assigning the unsupported URL.
NSError * err;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&err];
NSString *myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// This line is the answer.
myString = [myString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSString *uploadUrl = [NSString stringWithFormat:#"<MY host URL>"?data=%#",myString];
[JSONHTTPClient postJSONFromURLWithString:uploadUrl params:nil
completion:^(NSDictionary *json, JSONModelError *err)
{
if(err == nil)
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"success" message:#"uploaded" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
completionHanldler(json);
}
else
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Failed" message:#"uploaded" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
NSMutableDictionary *errorDict=[[NSMutableDictionary alloc]init];
if(err.code==-1009)
[errorDict setObject:#"The Internet connection appears to be offline."forKey:#"error"];
else
[errorDict setObject:#"Error occurred. Please try again!"forKey:#"error"];
completionHanldler(errorDict);
}
}];
Reviewing your question and API. you want to send some information to backend, you need to POST information using POST method and your data as json format.
you can test request using any online API Proxies (eg. POSTMAN or hurlit).
I hope its clear to you, you can't send more than 256 bytes using GET request, and as your API is POST request. In your existing method make following changes and you are done.
NSString *uploadUrl =#"<Your host URL>";
NSDictionary *dictParams = #{#"key" : #"value"};
[JSONHTTPClient postJSONFromURLWithString:uploadUrl params:dictParams
completion:^(NSDictionary *json, JSONModelError *err)
{
}];
Try this:
NSString *uploadUrl =#"<Your host URL>";
NSDictionary *val = #{<Add your params as key : value here>};
NSArray *innerParameter = #[val];
NSDictionary *parameter =#{#"Passports":innerParameter};
[JSONHTTPClient postJSONFromURLWithString:uploadUrl params:parameter
completion:^(NSDictionary *json, JSONModelError *err)
{
if(err == nil)
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"success" message:#"uploaded" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
NSError *error;
NSDictionary *resultDict = [NSJSONSerialization JSONObjectWithData:objectData options:NSJSONReadingMutableContainers error:&jsonError]; // this is a dictionary NOT the JSON
completionHanldler(resultDict);
}
else
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Failed" message:#"uploaded" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
NSMutableDictionary *errorDict=[[NSMutableDictionary alloc]init];
if(err.code==-1009)
[errorDict setObject:#"The Internet connection appears to be offline."forKey:#"error"];
else
[errorDict setObject:#"Error occurred. Please try again!"forKey:#"error"];
completionHanldler(errorDict);
}
}];
EDIT:
Same network call using AFNetworking
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *val = #{<Params as key : value>};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:#"<your host URL>" parameters:val success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
EDIT 2:
First of all, I figured the backend is done in POST but it is going through URL encoding. After much trial and error, this CANNOT be done, even after trying it in GET. As far as I can understand, the backend is not recognizing the POST method in JSON format, so you have to send it in URL encoding fashion only.
i have a method for http connection, which was working fine for me until the server i am trying to have an invalid ssl certificate.
Since i am using
[NSURLConnection sendSynchronousRequest:returningResponse:error]
There is no chance to pass authentication challenge by using NSURLConnection delegate methods.
Now, i need to change my service call code as fast as possible.
My method returns the data received from the connection, that is the major problem i can not easily change mine to
NSURLConnection to initWithRequest:delegate:
My service call method is as follows;
-(id)serviceCall:(NSString*)str withURL:(NSString*)serviceUrl withIdentifier:(NSString*)type
{
globalURL = [[NSURL alloc] initWithString:serviceUrl];
shouldAllowSelfSignedCert = YES;
// if(ISDEBUG) NSLog(#"%#",serviceUrl);
NSMutableDictionary* json;
NSURLResponse* response;
NSData* responseData = [NSMutableData data];
NSError* error = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:globalURL];
[request setHTTPMethod:#"POST"];
[request setHTTPBody: [str dataUsingEncoding: NSUTF8StringEncoding]];
NSString* msgLength = [[NSString alloc] initWithFormat:#"%lu", (unsigned long)[str length]];
[request addValue:#"text/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request addValue:msgLength forHTTPHeaderField:#"Content-Length"];
request.timeoutInterval = 180;
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if([type isEqualToString:#"image"])
{
if(ISDEBUG) NSLog(#"%#",responseData);
return responseData;
}
else
{
if(error)
{
UIAlertView *message = [[UIAlertView alloc] initWithTitle:NO_WS_CONNECTION message:#"" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
if(ISDEBUG) NSLog(#"%#",error);
}
else
{
if(responseData !=nil)
{
json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:NO_WS_CONNECTION delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
}
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if(ISDEBUG) NSLog(#"%#",responseString);
}
return json;
}
I hope i am clear enough.
What is your advise?
Thanks.
You should have a good reason to do it synchronously, so, I will try to help you without changing the flow.
Try wrapping the request into a class where you can implement the request using initWithRequest:delegate: and make the class return the response using block.
You will have something like:
[YourRequestClass requestWithURL:serviceURL callback:^(NSData *yourData, NSError *error){
}];
Ok, at this point you have a new tool that makes ASYNCHRONOUS requests, make the authentication challenge stuff for you and returns the result on a block.
Now, you can simply use dispatch_semaphore to block your thread until the request returns a response ....
-(id)serviceCall:(NSString*)str withURL:(NSString*)serviceUrl withIdentifier:(NSString*)type {
__block NSData *myData = nil;
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[YourRequestClass requestWithURL:serviceUrl callback:^(NSData *yourData, NSError *error){
//ignoring error (this is an example !)
myData = yourData;
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
//Use myData and make yourObject here!
return yourObject;
}
Note that It's just an example, and I'm just trying to pointing you the right way ... I didn't test this code, but I believe it should work as expected!
I am performing JSON POST request by clicking UIButton and after the submission, segue perform can be done. So, After submitting values, I cannot perform POST request anymore. It shows status code 200 and response is OK. But, data is not reflected in the Backend. Here is my code:
(IBAction)transitsurveydone:(id)sender {
if([tempArray count]!=0){
/* alert= [[UIAlertView alloc] initWithTitle:#"Survey Submission"
message:#"Please Enter your location"
delegate:self
cancelButtonTitle:#"Modify"
otherButtonTitles:#"Submit",nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
alert.tag=2;
[alert show];*/
NSLog(#"Caption array is %# %#",captionArray,tempArray);
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"myURL"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSMutableDictionary *postDict = [[NSMutableDictionary alloc]init];
NSMutableDictionary *d=[[NSMutableDictionary alloc] initWithObjectsAndKeys:#10,#"\"Bus\"", nil];
NSMutableArray *m=[[NSMutableArray alloc] init];
NSString *str1,*str2,*str3,*str4;
// Checking the format
if(tempArray.count==1){
for (int x=0; x<1; x++) {
str1=[NSString stringWithFormat:#"\"%#\"",[captionArray objectAtIndex:x]];
[d setObject:[tempArray objectAtIndex:x] forKey:str1];
}
[request setHTTPBody:[[NSString stringWithFormat: #"{\n \"instance\" : %#,\n \"response_method\": \"web\",\n \"routes\": [\n {%#:%#}\n ]\n}",randomString,str1,[d objectForKey:str1] ]dataUsingEncoding:NSUTF8StringEncoding]];
}
NSLog(#"%#:%#",str1,[d objectForKey:str1]);
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
// Handle error...
return;
}
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSLog(#"Response HTTP Status code: %ld\n", (long)[(NSHTTPURLResponse *)response statusCode]);
NSLog(#"Response HTTP Headers:\n%#\n", [(NSHTTPURLResponse *)response allHeaderFields]);
}
NSString* body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Response Body:\n%#\n", body);
}];
[task resume];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"~~~~~ Status code: %d", [response statusCode]);
if([response statusCode]==200){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Transit Survey submitted" delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alert.transform = CGAffineTransformMakeTranslation( 10, 740);
[alert show];
[self performSelector:#selector(dismissAlert:) withObject:alert afterDelay:1.0f];
submitteddonthide=NO;
}
else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Transit Survey Submission Failed" delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alert.transform = CGAffineTransformMakeTranslation( 10, 740);
[alert show];
[self performSelector:#selector(dismissAlert:) withObject:alert afterDelay:1.0f];
}
if([prefs integerForKey:#"humandone"]==1){
[self performSegueWithIdentifier:#"transittohuman" sender:nil];
}
else{
[self performSegueWithIdentifier:#"gobackfromtransit" sender:nil];
}
}
`
The above code is in IBAction
Your code looks fine and there is no any issues.
If this issue is happens all the time, add "Advanced Rest Client" add-on to chrome browser and test your server URL passing respective input values. If this process also can't be able to update values on your backend there should be some issue on your backend.
A couple of thoughts:
You are using status code to determine whether the server inserted the data correctly or not. You should actually have your web service build an affirmative response (in JSON, would be great) that says whether data was successfully inserted or not. You should not be relying solely on the web server's request response code.
I would observe the request with something like Charles and make sure it looks OK.
You're building a JSON request manually, which is very fragile. I would suggest using Charles to observe the request, and copy and paste it into http://jsonlint.com and make sure it's OK.
Even better, use NSJSONSerialization which is more robust and easier to use.
Also, you're sending this request twice. Lose this second request (you shouldn't do synchronous requests, anyway) and put all of your confirmation logic inside the session's completion handler block.
Yes. After struggling a bit, Clearing cookies helped me a lot :-
Here is a chunk of code, which is pretty much simple
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookiesForURL:[NSURL URLWithString:urlString]];
for (NSHTTPCookie *cookie in cookies) {
NSLog(#"Deleting cookie for domain: %#", [cookie domain]);
[cookieStorage deleteCookie:cookie];
}
Thank you Mr. reddys and Rob for the suggestions
I am using AFHTTPRequestOperationManager for login.
- (IBAction)loginAction
{
[TGProjectHandler clearCookies];
NSDictionary *params = #{#"Email": _email.text,
#"Password": _password.text,
#"IsRemember": #"true",
#"ReturnUrl": #"",
#"UserId": #0,
#"OutResponse": #0};
[_sharedHandler.requestManager POST:TGURL_LOGIN
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSError *e;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[operation.responseString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&e];
NSLog(#"%#\n\n%#", jsonDict, responseObject);
NSString *outResponse = responseObject[#"Object"][#"OutResponse"];
if (outResponse.integerValue == 1){
NSLog(#"login successful: %#", outResponse);
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"User_Logged_In"];
[TGProjectHandler saveCookiesToDefaults];
[self performSegueWithIdentifier:#"HomePage" sender:self];
}else
{
[[[UIAlertView alloc] initWithTitle:#"Login Failed" message:#"Invalid credentials" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[TGProjectHandler dismissHUD];
[[[UIAlertView alloc] initWithTitle:#"Login Failed" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}];
}
The service function returns UserID, but this is what I am getting in response while NSLog.
NSLog(#"%#\n\n%#", jsonDict, responseObject);
Object = {
OutResponse = 1;
ReturnUrl = "<null>";
};
Success = 1;
}
{
Object = {
OutResponse = 1;
ReturnUrl = "<null>";
};
Success = 1;
}
Why is UserId not coming in response?
By looking at your code I guess the problem might be content type in your request. Check if your content type is set properly.
For Example -
[_sharedHandler.requestSerializer setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
Also you can change response serializer to AFJSONResponseSerializerwhich will automatically convert your response to dictionary or array.
_sharedHandler.responseSerializer = [AFJSONResponseSerializer serializer];
I am having trouble creating a folder in box.com Here is my code. I am having trouble with foldersManager createFolderWithRequestBuilder If I breakpoint on the return I get "op = POST https://api.box.com/2.0/folders"
- (void)boxAPIAuthenticationDidSucceed:(NSNotification *)notification
{
NSLog(#"Received OAuth2 successfully authenticated notification");
BoxOAuth2Session *session = (BoxOAuth2Session *) [notification object];
NSLog(#"Access token (%#) expires at %#", session.accessToken, session.accessTokenExpiration);
NSLog(#"Refresh token (%#)", session.refreshToken);
dispatch_sync(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
BoxFolderBlock success = ^(BoxFolder *folder)
{
[self fetchFolderItemsWithFolderID:self.folderID name:self.navigationItem.title];
};
BoxAPIJSONFailureBlock failure = ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSDictionary *JSONDictionary)
{
NSLog(#"folder create failed with error code: %i", response.statusCode);
if (response.statusCode == 409)
{
dispatch_sync(dispatch_get_main_queue(), ^{
UIAlertView *conflictAlert = [[UIAlertView alloc] initWithTitle:#"Name conflict" message:[NSString stringWithFormat:#"A folder already exists with the name %#.\n\nNew name:", #"ezMedRecords"] delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
conflictAlert.alertViewStyle = UIAlertViewStylePlainTextInput;
[conflictAlert show];
});
}
};
BoxFoldersRequestBuilder *builder = [[BoxFoldersRequestBuilder alloc] init];
builder.name = #"ezMedRecords";
builder.parentID = self.folderID;
BoxAPIJSONOperation *op;
op = [[BoxSDK sharedSDK].foldersManager createFolderWithRequestBuilder:builder success:success failure:failure];
return;
}
What is self.folderID?
It should be a valid folderID of the folder that exists on Box.
To save to "all files", start with builder.parentID = #"0";
BTW, what is error message that you get in your failure block?
Does failure block execute at all?
I'm talking about this line:
NSLog(#"folder create failed with error code: %i", response.statusCode);