Recreate JSON data in Objective-C - objective-c

I'm trying to build an app on the Feedly API. In order to be able to mark categories as read, I need to post some data to the API. I'm having no success, though.
This is what the API needs as input:
{
"lastReadEntryId": "TSxGHgRh4oAiHxRU9TgPrpYvYVBPjipkmUVSHGYCTY0=_1449255d60a:22c3491:9c6d71ab",
"action": "markAsRead",
"categoryIds": [
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/photography"
],
"type": "categories"
}
And this is my method:
- (void)markCategoryAsRead: (NSString*)feedID{
NSLog(#"Feed ID is: %#", feedID);
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [standardUserDefaults objectForKey:#"AccessToken"];
NSString *feedUrl = [NSURL URLWithString:#"https://sandbox.feedly.com/v3/markers"];
NSError *error = nil;
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"markAsRead", #"action",
#"categories", #"type",
#[feedID], #"categoryIds",
#"1367539068016", #"asOf",
nil];
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
NSLog(#"Postdata is: %#", postdata);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:feedUrl];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request addValue:accessToken forHTTPHeaderField:#"Authorization"];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *errror = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&errror];
NSLog(#"Response code: %ld", (long)[response statusCode]);
if ([response statusCode] >= 200 && [response statusCode] < 300)
{
NSLog(#"It's marked as read.");
} else {
if (error) NSLog(#"Error: %#", errror);
NSLog(#"No success marking this as read. %#", response);
}
}
It keeps throwing a 400 error though, saying bad input. What am I doing wrong?

You're not doing anything with postdata after creating it. Attach it to the request.
[request setHTTPBody:postData];

There are a few problems in your code. Here are some I noticed:
You're not using postData.
The dictionary you make in tmp doesn't look like the dictionary you said you wanted to send. Where's lastReadEntryId, for example?
NSString *feedUrl should be NSURL *feedUrl
Stylistically, you should be using the dictionary literal syntax to create your dictionary. This will make it easier to debug.

Related

How to check JSON post return value

I am new to JSON and I am trying to send a post I am wondering if how can I check if I did it properly or check the return value of it. Here's what I've done
NSURL *url = [NSURL URLWithString:#"http://json.myurl.com/.....];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"email", #"Email",
#"password", #"FirstName",
nil];
NSError *error;
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
[request setHTTPBody:postdata];
For a beginner, I would recommend using third party framework, widely used by iOS developers across the world, called AFNetworking.
By using AFNetworking, HTTP requests are simple as that:
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[manager POST:url parameters:parameters progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
// TODO: Parse success here!
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// TODO: Parse failure here!
}];
In given example, object responseObject is a representation of API response JSON object.
Installation and further usage instructions of AFNetworking can be found in their website.
To check JSON POST return value:
NSString *strUrl=[NSString stringWithFormat:#"http://json.myurl.com/....."];
NSString *webStringURL = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:webStringURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"email", #"Email",
#"password", #"FirstName",
nil];
NSError* error;
NSData* postData = [NSJSONSerialization dataWithJSONObject:tmp options:NSJSONWritingPrettyPrinted error: &error];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[postData length]];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *jsonData, NSError *error)
{
if (!error)
{
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&error];
dispatch_async(dispatch_get_main_queue(),^
{
NSLog(#"jsonResponse--->%#",jsonResponse);
});
}
else
{
dispatch_async(dispatch_get_main_queue(),^
{
NSLog(#"error--->%#",error.description);
});
}
}];
And to check you JSON format is correct or not go through this link

Posting JSON data to server

I am trying to post and JSON data to server.
My JSON is:
{
“username”:”sample”,
“password” : “password-1”
}
The way I am sending it to server is:
NSError *error;
NSString *data = [NSString stringWithFormat:#"{\"username\":\"%#\",\"password\":\"%#\"}",_textFieldUserName.text,_textFieldPasssword.text];
NSData *postData = [data dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSData *jsonData = [NSJSONSerialization JSONObjectWithData:postData options:0 error:&error];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"My URL"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:jsonData];
NSURLResponse *requestResponse;
NSData *requestHandler = [NSURLConnection sendSynchronousRequest:request returningResponse:&requestResponse error:nil];
NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:requestHandler options:0 error:&error];
NSLog(#"resposne dicionary is %#",responseDictionary);
NSString *requestReply = [[NSString alloc] initWithBytes:[requestHandler bytes] length:[requestHandler length] encoding:NSASCIIStringEncoding];
NSLog(#"requestReply: %#", requestReply);
The JsonData that is created is a valid JSON accepted by the server.
But the app is crashing and the error is:
-[__NSCFDictionary length]: unrecognized selector sent to instance 0x1702654c0
what is wrong that i am doing here?
I always use this method in my apps to perform API calls. This is the post method. It is asynchronous so you can specify a callback to be called when the server answer.
-(void)placePostRequestWithURL:(NSString *)action withData:(NSDictionary *)dataToSend withHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *error))ourBlock {
NSString *urlString = [NSString stringWithFormat:#"%#", action];
NSLog(#"%#", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dataToSend options:0 error:&error];
NSString *jsonString;
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSData *requestData = [NSData dataWithBytes:[jsonString UTF8String] length:[jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)[requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:ourBlock];
}
}
You can easily call it:
- (void) login:(NSDictionary *)data
calledBy:(id)calledBy
withSuccess:(SEL)successCallback
andFailure:(SEL)failureCallback{
[self placePostRequestWithURL:#"yourActionUrl"
withData:data
withHandler:^(NSURLResponse *response, NSData *rawData, NSError *error) {
NSString *string = [[NSString alloc] initWithData:rawData
encoding:NSUTF8StringEncoding];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger code = [httpResponse statusCode];
NSLog(#"%ld", (long)code);
if (!(code >= 200 && code < 300)) {
NSLog(#"ERROR (%ld): %#", (long)code, string);
[calledBy performSelector:failureCallback withObject:string];
} else {
NSLog(#"OK");
NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:
string, #"id",
nil];
[calledBy performSelector:successCallback withObject:result];
}
}];
}
And finally, you invocation:
NSDictionary *dataToSend = [NSDictionary dictionaryWithObjectsAndKeys:
_textFieldUserName.text, #"username",
_textFieldPasssword.text, #"password", nil];
[self login:dataToSend
calledBy:self
withSuccess:#selector(loginDidEnd:)
andFailure:#selector(loginFailure:)];
Don't forget to define your callbacks:
- (void)loginDidEnd:(id)result{
NSLog(#"loginDidEnd:");
// Do your actions
}
- (void)loginFailure:(id)result{
NSLog(#"loginFailure:");
// Do your actions
}
First you create an NSString* that is supposed to contain JSON data. This doesn't work in general if the username and password contain any unusual characters. For example, I make sure that I have a quotation mark in my password to make sure that stupid software crashes.
You turn that string into an NSData* using ASCII encoding. So if my username contains any characters that are not in the ASCII character set, what you get is nonsense.
You then use the parser to turn this into a dictionary or array, but store the result into an NSData. Chances are that the parse fails and you get nil, otherwise you get an NSDictionary* or an NSArray*, but most definitely not an NSData*.
Here's how you do it properly: You create a dictionary, and then turn it into NSData.
NSDictionary* dict = #{ #"username": _textFieldUserName.text,
#"password": _textFieldPasssword.text };
NSError* error;
NSData* data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
That's it.
try this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:#"My URL"];
if (!request) NSLog(#"Error creating the URL Request");
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:#"text/json" forHTTPHeaderField:#"Content-Type"];
NSLog(#"will create connection");
// Send a synchronous request
NSURLResponse * response = nil;
NSError * NSURLRequestError = nil;
NSData * responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&NSURLRequestError];

Trying to login to a website in iOS app, no JSON response

I'm trying to login to a website and get a response using JSON using this code:
#try {
if([[txtUsername text] isEqualToString:#""] || [[txtPassword text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter both Username and Password" :#"Login Failed!"];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"username=%#&password=%#",[txtUsername text],[txtPassword text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"https://yedion.afeka.ac.il/yedion/fireflyweb.aspx?prgname=login"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [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];
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1)
{
NSLog(#"Login SUCCESS");
[self alertStatus:#"Logged in Successfully." :#"Login Success!"];
} else {
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Login Failed!"];
}
} else {
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#"Login Failed!"];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#"Login Failed!"];
}
In the log I can see there is no JSON response so I can't know if the login was successful or not.
Is there any other way to login to this website and get a response wether or not it was successful?
Thanks!
The code seems ok to me but do check the web service and also check that you give correct keywords for json if the key given to the objectForKey and your key in web service are different you will never get a json response.
Use Get method and try
[ request setHTTPMethod:#"GET" ];

JSON to Objective-C Dictionary

I'm making URL Request to an API but I dont know how to render the JSON, It generates an array of multiple users like this [{"user": "value"}, {"user":"value"}] and I was trying to use a TableView so I need an NSDictionary but i think is better to render a JSON like {users: [{"user": "value"}, {"user":"value"}]}. I have this code to make the request
#import "JSONKit.h"
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
users = [[jsonData objectFromJSONData] objectForKey:#"users"];
usersKeys = [users allKeys];
but I'm getting this error
2012-09-16 18:51:11.360 tableview[2979:c07] -[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180
2012-09-16 18:51:11.362 tableview[2979:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180'
I dont really know how to accomplish this so any help is useful, thanks
You are getting that error because whatever got parsed out of "jsonData" isn't necessarily what you expected (i.e. a dictionary).
Perhaps you need some error checking in that code of yours.
For example:
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(jsonData)
{
id objectReturnedFromJSON = [jsonData objectFromJSONData];
if(objectReturnedFromJSON)
{
if([objectReturnedFromJSON isKindOfClass:[NSDictonary class]])
{
NSDictionary * dictionaryFromJSON = (NSDictionary *)objectReturnedFromJSON;
// assuming you declared "users" & "usersKeys" in your interface,
// or somewhere else in this method
users = [dictionaryFromJSON objectForKey:#"users"];
if(users)
{
usersKeys = [users allKeys];
} else {
NSLog( #"no users in the json data");
}
} else {
NSLog( #"no dictionary from the data returned by the server... check the data to see if it's valid JSON");
}
} else {
NSLog( #"nothing valid returned from the server...");
}
} else {
NSLog( #"no data back from the server");
}
I was thinking on something like this
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
JSONDecoder *decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray *json = [decoder objectWithData:jsonData];
NSMutableArray *objects = [[NSMutableArray alloc] init];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSDictionary *user in json) {
[objects addObject:[user objectForKey:#"user" ]];
[keys addObject:[user objectForKey:#"value" ]];
}
users = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSLog(#"users: %#", users);
usersKeys = [users allKeys];
But it doesnt look efficient for many items or im wrong?

iphone SDK: How to post data to a url?

This may be a duplicate question but i could not find my answer when searching. So, How do i post data to a url? Heres what i got so far:
NSString *url = #"https://localhost/login.php";
NSURL *urlr = [NSURL URLWithString:url];
NSMutableURLRequest *urlre = [[NSMutableURLRequest alloc] init];
[urlre setURL:[NSURL URLWithString:url]];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSString *user = [defs stringForKey:#"User"];
NSString *pass = [defs stringForKey:#"Pass"];
NSInteger *version = [defs integerForKey:#"Version"];
NSString *bodyData = [[NSString alloc] initWithFormat:#"user=%#&password=%#&version=%d",user,pass,version];
NSData *body = [bodyData dataUsingEncoding:NSASCIIStringEncoding];
NSURLResponse *response = nil;
NSError *error = nil;
[urlre setHTTPMethod:#"POST"];
[urlre setValue:[[NSString alloc] initWithFormat:#"%d",[body length]] forHTTPHeaderField:#"Content-Length"];
[urlre setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[urlre setHTTPBody:body];
NSData *dataThis = [NSURLConnection sendSynchronousRequest:urlre returningResponse:&response error:&error];
if(dataThis)
{
NSLog(#"Connect Success");
} else {
NSLog(#"%#",[error localizedDescription]);
}
Is the above correct? In my
-(void) connection:(NSURLConnection*)connection didReceiveData:(NSData *)data
event, I get nothing. Even in the didFinishLoading it gets nothing with NSLog. Please help.
Have you set a delegate for your request?
Why don't you have a look at using a framework like ASIHTTPRequest, makes things so simple. Check it out http://allseeing-i.com/ASIHTTPRequest/