Sending multiple arguments to Drupal REST Services from iPhone - iphone

I am trying to access a Drupal service that takes more than one argument. The method is views.get and the server I'm using is REST 6.x-2.0-beta3. I am retrieving data from the server for 0 or 1 arguments with no trouble. Any argument after the first, however, is simply ignored. I have tested the view on the Drupal site, and it limits results correctly for every argument passed.
I've come to the conclusion that my problem must be the formatting, but I've tried nearly everything I can think of, not to mention a dozen suggestions I've found while Googling for an answer. My code is below:
responseData = [[NSMutableData data] retain];
NSMutableString *httpBodyString =[[NSMutableString alloc] initWithString:#"method=views.get&view_name=apps&args=1&display_id=default"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://drupalserver.com/services/rest/service_views/get.json"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];
[httpBodyString release];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
I have tried:
args=1,2
args=[1,2]
args="1,2"
args=["1","2"]
and several others along that vein. Does anyone know the proper way to do this?

You should considering using, https://github.com/workhabitinc/drupal-ios-sdk

Related

How to POST multiple requests with XML parser?

I want to POST 3 requests within same class with XML parser. I can manage to do only one request at a time. When I POST multiple requests, it says Parser Error. This is how I tried.
NSURL *url = [[NSURL alloc] initWithString:getAllFoodsURL];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *paramDataString = [NSString stringWithString:
#"<GetNames><DeviceId>1234</DeviceId><UserId>200</UserId></GetNames>"];
[req addValue:#"application/xml" forHTTPHeaderField:#"content-type"];
[req setHTTPMethod:#"POST"];
NSData *paramData = [paramDataString dataUsingEncoding:NSUTF8StringEncoding];
[req setHTTPBody: paramData];
NSURLConnection *theConnection=[[NSURLConnection alloc]initWithRequest:req delegate:self];
if (theConnection) {
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData=data;
[data release];
}
I have used NSXMLParser delegates methods. After one request is completed(connection release), then I create another connection and do the same process for second request.
But it doesnot work.
I want to know, how to manage multiple requests with NSXMLParser?
If you can give me a code example, its highly appreciated.
I guess NSThread is what you are looking for.
But I am not sure as I am not much aware about that.
Note that NSXMLParser isn't involved in HTTP requests -- do you mean NSURLRequest instead? You'll need to make your requests separately, possibly using separate blocks, operations, or threads.
Once you've retrieved the data for each request, you'll need to use separate NSXMLParser objects for each. A single instance of NSXMLParser is tied to its XML data at initialization -- you can't reuse a parser. You can use the same delegate for all your xml parsers, and the delegate can use the first parameter to each of the xml parser delegate methods (i.e. parser) to know which parser is calling a given method.

Post Data format is diffrent then what I needed

I am having a simple problem while making a request to server for updating a name field. I need to post some data in this format:-
{"api_token"=>"api", "device_token"=>"device", "user"=>{"name"=>"mohit"}, "id"=>"4"}
But when i am trying to post something its posting in this format:-
{"user"=>"(\n {\n name = ChangeName;\n }\n)", "api_token"=>"api", "device_token"=>"device", "id"=>"4"}
I am not able to figure out how to change my code to generate proper request. Here is the code that I am using.
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:#"http://localhost:3000/users/4?api_token=api&device_token=device"]];
NSMutableDictionary *dict= [NSMutableDictionary dictionaryWithObjectsAndKeys: #"Mike",#"name", nil];
NSArray *array=[[NSArray alloc]initWithObjects:dict, nil];
[request setPostValue:array forKey:#"user"];
[request setRequestMethod:#"PUT"];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestFinished:)];
[request startAsynchronous];
Please let me know if i need to post some more code fragments.
ASIFormDatRequest setPostValue:forKey: wants strings, not structures. It ends up calling description to convert them to strings and you're getting the printable description of an array with a dictionary in it.
Rails uses a naming scheme that allows you to simulate a hierarchy in a flat space using a field naming convention detailed at http://guides.rubyonrails.org/form_helpers.html. You should read that and understand the html produced by the form helpers.
Try:
[request setPostValue:#"mohit" forKey:#"user[name]"];
and rails will unpack it into the proper kind of collection on the server.

Trying to upload image from iPhone to server using ASIFormDataRequest

I'm trying to use ASIFormDataRequest to send a photo image from my
iPhone app to my server.
When I do so, the server sends back an error
message saying, "must be an image file," implying that there is
something wrong with the formatting of my image. (Of course, that
might not be the problem...but it's a good place to start.) I know
there's no "problem," per se, on the server, because a previous
approach I used (non-ASIHTTPRequest-based) worked fine.
Here's my iPhone code:
ASIFormDataRequest* request = [ASIFormDataRequest requestWithURL:
[NSURL URLWithString:photoUploadURLString]];
request.username = self.username;
request.password = self.password;
[request setPostValue:self.place.placeId forKey:#"place_id"];
NSData* jpegImageData = UIImageJPEGRepresentation(self.photo,
PHOTO_JPEG_QUALITY);
NSString* filename = [NSString stringWithFormat:#"snapshot_%#_
%d.jpg", self.place.placeId, rand()];
[request setData:jpegImageData withFileName:filename
andContentType:#"image/jpeg" forKey:#"snapshot[image]"];
request.uploadProgressDelegate = self.progressView;
[request startSynchronous];
Anyone see anything wrong with this? (I'm fairly new to this stuff, so
there could be something obvious I'm missing.)
Thanks very much.
Have you ever try addData instead of setData, It worked on my solution.
[request addData:jpegImageData withFileName: filename andContentType:#"image/jpeg" forKey:#"photos"];
Edit: By the way, which server side are you using ?
Your problem might be inside of the your key forKey:#"snapshot[image]"] try to dummy variable key like forKey:#"mysnapshot"]
Hope this helps

I need the correct syntax for the setValue:forHTTPHeaderField: method on NSMutableURLRequest

I am pulling my hair out trying to conjure up the correct syntax to set the HTTP header information do a byte-range load from an HTTP server.
This is the offending method on NSMutableURLRequest
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field
This is how I am using this method to load the first 512 byte of a URL request.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"GET"];
[request setValue:#"0-512\r\n" forHTTPHeaderField:#"Range"];
So far it is ignored and I always receive the entire data payload. I just want the range of bytes specified (0 - 512). Can someone please relieve my headache?
Update:
I have used curl to confirm that my web server supports byte ranges thusly:
curl --range 0-2047 http://www.somewhere.com/humungodata.dat -o "foobar"
The file size of foobar is 2048
Cheers,
Doug
Problem solved.
By adding additional header fields the code immediately worked correctly. Why? Dunno. But it works:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"GET"];
[request setValue:#"keep-live" forHTTPHeaderField:#"Connection"];
[request setValue:#"300" forHTTPHeaderField:#"Keep-Alive"];
[request setValue:#"bytes=0-2047" forHTTPHeaderField:#"Range"];
Your original code was wrong in the setValue line, it should be #"bytes=0-512". In your followup, you used the correct string, so the other headers should not be needed.
What you have there should be the correct way to add a header value to a URL request, however i thought only posts got header values, maybe im wrong, have you tried doing this on other enviroments and gotten it to work? Maybe take out the \r\n?

NSURLConnection is run many times

I connect asynchronously with server each 5 seconds. The URL is the same, but POST-body is changed each time. Now I create NSURL, NSURLRequest and NSURLConnection from the scratch each time.
I think it'd be more effective to set connection once and just use that one further.
I am a newbie and not sure if that possible. There is no mutable NSURLConnection, but may it's need to create NSURLConnection like:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
and change NSMutableURLRequest POST-data to send another request to server.
Which way is right?
I assume what you're concerned about is the overhead of creating the HTTP connection. NSURLConnection is smart enough to handle this for you using HTTP/1.1 and reusing existing connections. It does not use pipelining last time I checked, but for your purpose, connection reuse should be sufficient. I do encourage you to put a network sniffer on this and make sure that it's working as you want them to.
The cost of creating the objects themselves is trivial on the order of once per 5s and you shouldn't try to optimize that (though of course you should reuse the NSURL). It's the opening a connection to the server that's expensive, especially on iPhone.
If you find you really do need pipelining, you unfortunately will have to roll your own. I've heard that CFHTTPStream can do it, but I don't see a lot of evidence of that. CocoaAsyncSocket is your best bet for low-level access to the sockets without having to write low-level code.
Since latency on the cell network can be very bad, it's possible that your connection will take longer than 5s to complete. Do make sure that one connection is done before starting the next, or you'll start making more and more open connections.
Just to clarify things, NSURLConnection will reuse existing sockets, but only for a relatively small time frame (12 seconds). If you send a request, get back a response, and send a subsequent request within 12 seconds that 2nd request will got out on the same socket. Otherwise the socket will be closed by the client. A bug has been filed with Apple to increase this timer or to make it configurable.
#Rob Napier #Eric Nelson
As you mentioned: "NSURLConnection is smart enough to handle this for you using HTTP/1.1 and reusing existing connections".
However, I can not find such description in any Apple's document about that.
To make thing clear, I write some code to test it:
- (IBAction)onClickSend:(id)sender {
[self sendOneRequest];
}
-(void)sendOneRequest {
NSURL *url = [NSURL URLWithString:#"http://192.168.1.100:1234"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
[request addValue:[Base64 encodeFromString:kValueVersion] forHTTPHeaderField:kKeyVersion];
[request addValue:[Base64 encodeFromString:kValueDataTypeCmd] forHTTPHeaderField:kKeyDataType];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyCmdName];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyDeviceName];
[request addValue:[Base64 encodeFromString:#"xxdafadfadfa"] forHTTPHeaderField:kKeyDTLCookies];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
And then, I start wireshark to catch packages on the server(192.168.1.xxx), using "(tcp.flags.syn==1 ) || (tcp.flags == 0x0010 && tcp.seq==1 && tcp.ack==1)" to filter tcp 3-way hand shake. Unfortunately, I can see the 3-way hand shake for each calling of "sendOneRequest". Which means, the NSURLConnection seems not reuse the existing connections. Can some one point out what's wrong in my code and how to send multiple requests via one socket connection by NSURLConnection?
I also tried synchronous way to send request:
-(void)sendOneRequest {
NSURL *url = [NSURL URLWithString:#"http://192.168.1.100:1234"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
[request addValue:[Base64 encodeFromString:kValueVersion] forHTTPHeaderField:kKeyVersion];
[request addValue:[Base64 encodeFromString:kValueDataTypeCmd] forHTTPHeaderField:kKeyDataType];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyCmdName];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyDeviceName];
[request addValue:[Base64 encodeFromString:#"xxdafadfadfa"] forHTTPHeaderField:kKeyDTLCookies];
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
sleep(1);
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
sleep(1);
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
}
And the result is the same.
=======UPDATE============================
Finally, I found the reason why my test is different from Rob and Eric say.
In short, Rob and Eric are correct. And NSURLConnection uses “keep-alive” as default for using HTTP/1.1 and reuses existing socket connection, but only for a relatively small time frame.
However, NSURLConnection has some problems for “chunked transfer-coding”(ie. without content-length).
In my test, server side send a response without content-length and response data, and it's chunked response and NSURLConnection will close the connection, thus 3-way hand shake occurs for each http post.
I changed my server code, set the length of response as 0, and the behavior is correct.
make a method that returns a request and do
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[self requestMethod] delegate:self];
?