POST JSON data to specific object iOS - ios

I have read several posts on Stack about how to POST data using both XML and JSON however nothing is standing out to me about how to update a selected object.
I am pulling down data from my boss' job tracking API fine, all things are accounted for. However I want to update individual selected object's variables.
Example:
If I have a recipe site API and I am pulling down 100 recipes and displaying the titles in a table. I select a row and it displays a new screen which shows all the details about the recipe with textfields for updating content and a button that will save to the website. How do I update an ingredient on the selected recipe so that it is represented on the website?
Bare in mind I am using my business' API and not Parse.com or another server based database.
I would prefer to use JSON however if there are better solutions using XML I am fine with that.
New Thought
Do I have to replace the entire object when updating?
More Info
Due to using an API, I do not have links directly to a specific object. I get given the block (100 recipes), have to iterate through the block to save each object as NSObject and then sort the newly stored NSObjects how I like to. When I select a row, I am selecting an object that has been sorted and displaying that objects contents. I don't know if this information is helpful or not.
The reason for this extra information is:
When trying to update the Object through the API, how do I know I am updating that specific object and not the entire list of objects?

I think you want to POST data onto the existing fields:
You can try this to POST the data:
NSString *post = [NSString stringWithFormat:#"text_field1=%#",text_field.text];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://your api to recieve the data into the fields"]]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if(conn) {
NSLog(#"Connection Successful");
} else {
NSLog(#"Connection could not be made");
}
}

I think you can use Mantle on GitHub.
https://github.com/Mantle/Mantle

Related

How to send HTTP body plain text for GET method?

I had a problem, I use the iGDB REST API which need to send some plain text for some endpoints with GET method.
There is no problem with PostMan (by selecting "Body" > "raw" & paste my query), but when I try with Objective-C, an error appear telling me "GET method must not have a body"...
Here is the code used in my app:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"MY_URL"]];
[request addValue:#"text/plain" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"GET"];
[request setHTTPBody:[#"sort popularity desc;" dataUsingEncoding:NSUTF8StringEncoding]];
EDIT 02/10/2019
Trying to add each filters in headers not working...
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"MY_URL"]];
[request setValue:[[#"id,name,first_release_date,release_dates,cover,platforms" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0] forHTTPHeaderField:#"fields"];
[request setValue:[[#"popularity desc" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0] forHTTPHeaderField:#"sort"];
[request setValue:[[#"5" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0] forHTTPHeaderField:#"limit"];
[request setValue:[[#"0" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0] forHTTPHeaderField:#"offset"];
Thanks in advance for any replies !
It's no longer possible to send a GET request with a body, you'll have to send the data via the query string of the URL, either by building the string manually or with the help of NS(Mutable)URLComponents.
As per the iOS 13 release notes, GET requests are no longer allowed to have a body:
All URLSessionTask instances with a GET HTTP method that contain a body now produce the error NSURLErrorDataLengthExceedsMaximum. (46025234)
This makes URLSession more conformant with the HTTP/1.1 RFC:
A message-body MUST NOT be included in
a request if the specification of the request method (section 5.1.1)
does not allow sending an entity-body in requests.
If I get true your question, you can set parameters to your request header when you get you can set like below.
[request addValue:#"valueForKey1" forHTTPHeaderField:#"key1"];
[request addValue:#"valueForKey2" forHTTPHeaderField:#"key2"];
If you send a data format so,
NSString *stringValueOfParameters =[NSString stringWithFormat:#"userName:blabla"];
NSData *convertedDat=[stringValueOfParameters dataUsingEncoding:NSUTF8StringEncoding];
NSString *headerValue=[NSString stringWithFormat:#"Basic %#",[convertedDat base64EncodedStringWithOptions:0]];
[request setValue:headerValue forHTTPHeaderField:#"headerKey"];
// Edit
You must try kinda like that, directly write a Dictionary or like below write your JSON parameters as NSString then convert it to Data.
NSDictionary *dictParams = #{ #"fields" : #[#"id",#"name",#"first_release_date",#"release_dates",#"cover",#"platforms"], #"sort" : #"popularity desc", #"limit": #5, #"offset":#0 };
// this is taken from an example
NSString *jsonString = #"{\"ID\":{\"Content\":268,\"type\":\"text\"},\"ContractTemplateID\":{\"Content\":65,\"type\":\"text\"}}";
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
Then try it to set header.

Using NSURLSession to POST, what is the correct way to post the variables?

I am following this tutorial: http://www.raywenderlich.com/2965/how-to-write-an-ios-app-that-uses-a-web-service. Trying to set up a basic web service. Seems like the tutorial is old material and ASIHTTPRequest is no longer continued. I have been trying to use NSURLRequest instead. First question, is NSURLRequest a pretty standard way to be doing this? I just want something for basic GET, POST etc, should I be doing it a different way?
My code is:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"We want to unlock for the code %#",self.textField.text);
//Get a device ID, (actually can't do this aymore)
NSString *uniqueIdentifier = #"My iPhone";
NSString *code = self.textField.text;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.madasd.co/promos/"]];
request.HTTPMethod=#"POST";
//Set the header fields
[request setValue:#"application/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSString *myString = [NSString stringWithFormat:#"rw_app_id=1&code=%#&device_id=%#",code,uniqueIdentifier];
NSLog(#"%#",myString);
NSData *requestBodyData = [myString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody=requestBodyData;
//Create url and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn start];
return TRUE;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",string);
}
Second question, I have tested the backend using curl so I know it works fine, however the response I get is "Invalid Request", I think this is because the string I am sending is not correct. Am I doing this correct using the var names and & operators? Any pointers on this would be great! thanks. (Running a LAMP server on Linode!)
EDIT:
Also tried sending as JSON:
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
NSDictionary *mapData = [[NSDictionary alloc]initWithObjectsAndKeys:#"1",#"rw_app_id",code,#"code",uniqueIdentifier,#"device_id", nil];
NSError *error = nil;
NSData *requestBodyData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
request.HTTPBody=requestBodyData;
Still getting the same error.
A couple of thoughts:
Don't use NSURLConnection. It is deprecated as of iOS 9. Use NSURLSession. See Using NSURLSession in the URL Loading System Programming Guide.
Decide what type of request you need to prepare. You specified application/xml in your header, but are creating a application/x-www-form-urlencoded request. Your Content-Type header must match how you're building the HTTPBody.
What type of request does your server require? x-www-form-urlencoded? XML? JSON?
Also, what type of response does your server provide?
If building a application/x-www-form-urlencoded request (as suggested by the body of your request), you are not properly percent escaping the values (see https://stackoverflow.com/a/20398755/1271826).
If you use delegate based NSURLConnection or NSURLSession, you should not just grab the results in didReceiveData. What you need to do is
Instantiate a NSMutableData before starting the request;
Have didReceiveData merely append to that NSMutableData;
Only when connectionDidFinishLoading: (in NSURLConnection) or URLSession:task:didCompleteWithError: (in NSURLSession) is called, should you then use the NSMutableData.
Alternatively, if using the block-based NSURLSession, this concern is completely eliminated (since you're not implementing any delegate methods). Using completionHandler-based methods of NSURLSession is much easier.
If all of this is too complicated, you might consider using AFNetworking's AFHTTPSessionManager (but not AFHTTPRequestOperationManager) to build your requests. It gets you out of the weeds of properly building requests, implementing delegate methods, etc.
You might need to wrap the strings into a dictionary and get the NSData object from a call to NSJSONSerialization. Though it depends on the form expected by the server.

NSURLConnectionDelegate callback in one function

I'm trying to make my own Request class I intend to use throughout my app. Here is the code I've been coming up with so far.
-(IIWRequest *)initAndLaunchWithDictionnary:(NSDictionary *)dictionnary
{
self=[super init];
if (self) {
// Create the request.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://xxxxx.com/app/"]];
// Convert data
SBJsonWriter *jsonWriter = [[SBJsonWriter alloc] init];
NSString *jsonData = [jsonWriter stringWithObject:dictionnary];
NSLog(#"jsonData : %#",jsonData);
NSData *requestData = [jsonData dataUsingEncoding: NSUTF8StringEncoding];
request.HTTPBody = requestData;
// This is how we set header fields
[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];
// Create url connection and fire request
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[self activateNetworkActivityIndicator];
if (connection) {
NSLog(#"Connection");
} else {
NSLog(#"No connection");
}
}
return self;
}
I have included NSURLConnectionDelegate. I'd like to fire the connection callbacks such as did finished or did fail back to the function mentioned before. The goal of all that is to get only one method to call in the end looking like :
-(IIWRequest *)initAndLaunchWithDictionnary:(NSDictionary *)dictionary inBackgroundWithBlock:^(BOOL succeeded){}
Any idea ? Thanks !
Use block method of NSURLConnection class it will reduced your functionality as well sendAsynchronousRequest:queue:completionHandler:
Read this doc.
I would hardly suggest you to use one of the currently existing libraries for calling URLs. One of the best I know is AFNetworking https://github.com/AFNetworking/AFNetworking. There is lot of examples and its easy to use and I am sure you should go with it.
Anyway, if you want to build your own class I would suggest you to read post written by Kazuki Sakamoto here NSURLConnection and grand central dispatch.
Regards
If you are using the iOS 7, I recommend A LOT you to use NSURLSession classes, this new network api is really amazing and simple.
Anyway, to answer your question, you just need to hold the reference of callback in your class and call it when you receive some response from the server.
To hold the reference, you can do something like this:
// in your .h file
typedef void (^ResponseBlock)(BOOL success);
// in your .m, create a class extension and put declare the block to use it for callback
#interface MyClass ()
{
ResponseBlock callback;
}
// You can store reference using equal like this
- (void)myMethodRequestWithResponseBlock:(ResponseBlock)responseBlock
{
callback = responseBlock;
// statements
}
// And finally, you call back block simple like this:
callback(success);
Again, use NSURLSession api if you can, you will simplify your work.
I hope this may help you.
Cheers!

How to upload images in a scrollview onto a web server?

I have an iOS app that has a series of images in a scrollview (camera pictures). I want to be able to post these on to a url individually or collectively as a group.
Can someone point me to an example or some sample code that would get me started?
Much appreciated
in that case if you if you set up your server (how do this i don`t now, because i used quickblox - ready-made solution) try send GET-request to the server. You can try this like this:
(source - How to send a Get request in iOS? )
NSString *getString = [NSString stringWithFormat:#"parameter=%#",yourvalue];
NSData *getData = [getString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *getLength = [NSString stringWithFormat:#"%d", [getData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"https:yoururl"]];
[request setHTTPMethod:#"GET"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:getData];
self.urlConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
NSAssert(self.urlConnection != nil, #"Failure to create URL connection.");
// show in the status bar that network activity is starting
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
For more advanced preferences I would advise you try learn http://allseeing-i.com/ASIHTTPRequest/
For this you can create file server or use other maded. Look this: http://quickblox.com/ - they has blobs and ios api for their server, so download|upload files simple implemented in code.
First, you need register your account and then register your app.( https://admin.quickblox.com/signin ) (it's not difficult, few minuts)
Then, using instructions from site added Quickblox auth to your app and then use QBBlobs for dowload photo. Good luck!

Logging in from settings username and password preferences

I have an app that uses webView. In the home screen of a website I want to login using username and password entered by the user in the app's settings option. Currently I have this code which I saw in solution to a similar question asked on this forum. But it isn't working (neither it did for the other guy).
-(IBAction)cachepressed:(id)sender{
NSString *baseurl=[[NSUserDefaults standardUserDefaults] stringForKey:#"url_preference"];
NSString *username= [[NSUserDefaults standardUserDefaults] stringForKey:#"name_preference"];
NSString *password= [[NSUserDefaults standardUserDefaults] stringForKey:#"pswrd_preference"];
NSString* content = [NSString stringWithFormat:#"username=%#&password=%#", username, password];
NSData *data=[content dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postlength=[NSString stringWithFormat:#"%d",[data length]];
NSString *loginpage= [baseurl stringByAppendingString:#"/index.php?title=Special:UserLogin"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:loginpage]];
[request setHTTPMethod:#"POST"];
[request setValue:postlength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:data];
NSError *error=nil;
NSURLResponse *response=nil;
NSData *result=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *HTMLString = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
[webView loadHTMLString:HTMLString baseURL:[NSURL URLWithString:loginpage]];
}
I am not too sure about the two lines of code starting with [request setValue...]. Can somebody suggest a solution to this? It would be a great help. Thanks in anticipation.
This depends a lot on how the authentication is done on the website.
Based on what I can figure from your question, the code you posted sends values for the fields named "username" and "password" to the index.php?title=Special:UserLogin page using POST.
You need to make sure that everything is set accordingly.
1. Are your fields name the same on the website?
Maybe the login form uses different field names, not username and password. Check the source code and see if the input names are indeed "username" and "password"
2. Does your host allow posting data from a different source?
I used to set mine so no POST request would work if they didn't originate from my server, so POSTing data from an iPad would not have functioned.
Is this the case for you too?
3. The login process is really done by posting data to that page?
Maybe on the website the authentication is done using AJAX on a different php page and then you get redirected to index.php?title=Special:UserLogin, I've seen such cases in the past.
Bottom line is that you need to know exactly how the login is done on the website before doing it inside a webview. Correct me if I'm wrong, but based on your post it doesn't seem to be the case here

Resources