Sending JSON data through formData - Objective C - objective-c

I am sending videos to a server in my application. But the user is also entering information about the video. My question is how can I attach that to my formData to be sent to my server as a JSON?
AFHTTPClient *httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"mySite.com/dev/iphone/"]];
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:#"POST" path:#"downloadFileChallange.php" parameters:nil constructingBodyWithBlock:^(id <AFMultipartFormData>formData)
{
[formData appendPartWithFileData:webData name:#"file" fileName:newUsername mimeType:#"video/quicktime"]; <-- here is where I want to attach the information
}];
Suggestions, thoughts?

Create a dictionary and pass your parameters into the request object, e.g.,:
parameters = #{ #"loginName": self.loginName.text };

Related

AFNetworking 2.0 POST Issue

I am in the process of switching over some of my code from AFNetworking 1.0 to 2.0.
Before when doing a POST, I was creating an AFHTTPClient, and an AFHTTPRequestOperation like so:
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:reqUrl];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
httpClient.operationQueue.maxConcurrentOperationCount = 1;
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
req.viewName, #"viewName",
req.json, #"JSON",
req.dateAdded.description, #"dateTime",
req.latitude, #"latitude",
req.longitude, #"longitude",
req.heading, #"heading",
req.user, #"requestUser",
nil];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[op setCompletionBlockWithSuccess:
^(AFHTTPRequestOperation *operation,
id responseObject) {
.......convert responseObject (string) to NSDictionary.....
});
This worked fine, and my POSTs went through and I received a successful text response from the server. (which I then converted to a NSDictionary)
I now am using an AFHTTPSessionManager singleton, and calling the POST method from that. When initializing my AFHTTPSessionManager, I am doing the following:
AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
[self setResponseSerializer:responseSerializer];
self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"text/html", nil];
Then in my other class, I am calling the POST like so:
NSDictionary *params = #{
#"viewName":req.viewName,
#"JSON":req.json,
#"dateTime":req.dateAdded.description,
#"latitude":req.latitude,
#"longitude":req.longitude,
#"heading":req.heading,
#"requestUser":req.user
};
[netManager POST:path parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
.....
} failure:^(NSURLSessionDataTask *task, NSError *error) {
//failing here
});
My data has not changed at all, but the POSTs always fail with the error:
Error Domain=AFNetworkingErrorDomain Code=-1011 "Request failed: bad request (400)" UserInfo=0x1704675c0 {AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x178234660> { URL: ... } { status code: 400, headers {
"Content-Length" = 2738;
"Content-Type" = "text/html";
Date = "Thu, 15 May 2014 16:13:51 GMT";
Server = "Microsoft-IIS/7.0";
"X-Powered-By" = "ASP.NET";
Whats different that is causing the new AFNetworking 2.0 POST code to not work with this now? Is there anything I need to be setting? The URL and Parameters I am passing are the same as they were with the old way I was sending the POST.
Thanks
My solution ended up being a pretty simple one
In my AFHTTPSessionManager's init, I was not setting the RequestSerializer along with the ResponseSerializer.
After setting it correctly, my POSTs are going through fine again. Heres what I set:
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];
self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"application/json", nil];
[self setRequestSerializer:[AFJSONRequestSerializer serializer]];
EDIT
Aaron Brager stated that those first 2 lines are defaults and not needed. All I needed was to set the RequestSerializer. I tested and can verify this.

sending JSON using simple RKClient post

I'm trying to send a request using RestKit. I want it to be sent in JSON, but it seems that default post methot from RKClient uses some kind of FORM data formatting (I check it using [request HTTPBodyString]).
I need to send the data using simple POST, like this (I'm not using object mapping):
[[RKClient sharedClient] post:path usingBlock:^(RKRequest* req) {
req.params = params;
req.delegate = self;
}];
I found some solutions that use NSJSONSerialization, but that method crashes when I put NSDate object in my JSON dictionary.
Is there a way to tell the RKClient to send requests using JSON?
Update: params is a NSDictionary. I want to be able to tell RestKit to serialize my dictionary using JSON when sending it by POST.
You can do this by setting the RestKit's serializationMIMEType property to RKMIMETypeJSON.
E.g.
[RKObjectManager sharedManager].acceptMIMEType = RKMIMETypeJSON;
[RKObjectManager sharedManager].serializationMIMEType = RKMIMETypeJSON;
see also http://restkit.org/api/master/Classes/RKObjectManager.html:
The desired serialization format is configured by setting the
serializationMIMEType property. RestKit currently supports
serialization to RKMIMETypeFormURLEncoded and RKMIMETypeJSON.
Update:
Example for posting a plain JSON String with the correct Mime Type:
RKParams *params = [RKRequestSerialization serializationWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
MIMEType:RKMIMETypeJSON];
[[RKObjectManager sharedManager].client post:#"/mypath"
params:params
delegate:self];
Update 2:
Getting JSON from a NSDictionary object:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myNSDictionaryObject
options:NSJSONWritingPrettyPrinted
error:&error];
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

AFNetworking post request not getting through to Sinatra app

I'm trying to post a request from my iPhone with a Sinatra API I made. Currently all my Sinatra app is doing is printing out the request that has been sent to it. This is the code for that:
post '/profile' do
puts "#{params}"
end
My objective-c is pretty simple as well. All it does is send a post request to my API:
NSURL *url = [NSURL URLWithString:kBaseURLString];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:JSON, #"json", nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"/profile" parameters:dictionary];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"SUCCESS");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#", error);
}];
[operation start];
When JSON (in line 3 of the obj-c) is a very short string, such as #"test", Sinatra prints it out correctly like this:
{"json"=>"test"}
When I use the actual JSON profile data, which is a very long JSON blob, Sinatra prints it out as this:
{"json"=>"(null)"}
I can't figure out why the long blob is getting through. I am 100% sure that i'm passing the correct string, but Sinatra is not receiving it. My current theory is that Sinatra has a max character limit on requests, but I am new to Sinatra and Ruby, and I have no idea how I'd test that. What is going wrong?
UPDATE:
First off, thanks Kjuly for your suggestions. I figured out that I was wrong on the character limit on Sinatra thing. In obj-c I'm doing a log of the dictionary that has the JSON blob on line 3, and it has the json blob. However, when I log the body of the NSMutableURLRequest on line 4, the body is empty. When I use my tiny JSON blob, the body is filled.
Does NSMutableURLRequest have a character limit? Can anyone think of a reason why it would not accept my very large dictionary with the large JSON blob, but not with the small one.
Thanks!
UPDATE AGAIN:
The request body now fills correctly. I had to add this line into line 3:
[httpClient setParameterEncoding:AFJSONParameterEncoding];
Now I am getting this response back in the HTTPResponse from Sinatra:
Error Domain=com.alamofire.networking.error Code=-1016 "Expected content type {(
"text/json",
"application/json",
"text/javascript"
)}, got text/html"
Sinatra is now just printing
{}
Instead of {"json"=>"(null)"}
Still not sure what's going on.
Update 3
Okay, what I thought was the HTTPResponse from Sinatra - the text/json stuff - was because I was returning a text/html from Sinatra back in AFNetworking. I have now checked the body that Sinatra is receiving, and my giant JSON blob is in there. However, "params" is still empty.
Anyone have any idea why?
FIXED IT
Looks like when you post JSON to sinatra you have to read the body of the request directly. In Sinatra, you do this like so:
profile = JSON.parse(request.body.read.to_s)
Then profile is your parsed object.
I think you need to use AFJSONRequestOperation instead, here's a sample code:
// Fetch Data from server
NSURL *url = [NSURL URLWithString:#"https://gowalla.com/users/mattt.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation * operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest * request, NSHTTPURLResponse * response, id JSON) {
NSLog(#"Name: %# %#", [JSON valueForKeyPath:#"first_name"], [JSON valueForKeyPath:#"last_name"]);
}
failure:nil];
[operation start];
Or you can visit the WIKI PAGE, see Step 4: Download and Parse JSON.

ARC Issue: No known instance method for selector 'appendPartWithFileData:mimeType:name:'

When following the AFNetworking example to upload a form:
NSURL *url = [NSURL URLWithString:#"https://www.example.com/"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
keyField.text, #"key",
valField.text, #"val",
nil];
NSData *imageData = UIImagePNGRepresentation(image);
NSURLRequest *request = [client multipartFormRequestWithMethod:#"POST"
path:#"/upload"
parameters:params
constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData
mimeType:#"image/png"
name:#"avatar"];
}];
Compilation returns error:
ARC Issue: No known instance method for selector 'appendPartWithFileData:mimeType:name:'
How can I fix it?
It’s a bit strange that the compiler considers this an “ARC issue”. IMHO the AFMultipartFormData protocol doesn’t contain a method called appendPartWithFileData:mimeType:name:. Take a look at the documentation, maybe the protocol was refactored and the method signature change a bit. I’m not sure where does AFMultipartFormData come from, but a short search gave me these docs that suggest you might have success with appendPartWithFileData:name:fileName:mimeType:.
The signature in my AFHTTPClient.h looks like this:
- (void)appendPartWithFileData:name:fileName:mimeType:
and matches the documentation here. Could just be that the sample is outdated.
Update: See this SO answer: How do you upload multiple files with AFNetworking

ASIFormDataRequest - iOS Application. How do I RETRIEVE a post variable

So I have this url that leads to a .php
So far I managed to retrieve every single thing except the actual XML that I want. the XML is stored in a variable called _xml.
if($this->outMethod=="" || $this->outMethod=="POST") //Default to POST
{
$_POST["_xml"] = $_xml;
}
So I've already set the outMethod to POST but I don't understand how to retrieve the value within _xml.
- (void)grabURLInBackground
{
NSLog(#"grab url in background");
NSURL *url = [NSURL URLWithString:#"xxxxxxxxxxx"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"POST" forKey:#"outMethod"];
[request setPostValue:#"1" forKey:#"Entity_ID"];
[request setDelegate:self];
[request startAsynchronous];
NSLog(#"end of grabUrlInBackgroun");
}
don't worry the URL is right I just don't want to post it.
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"A");
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
if(responseString)
{
NSLog(#"responseData is not null");
}
NSLog(#"response string: %#", responseString);
//NSLog(#"%#", responseString);
}
What I get back is that the request is good, but there is no response in responseString. This is because my php does not want to print out any of the XML on screen in HTML but it stores the result in the variable _xml sent via post "$_POST["_xml"] = $_xml
My question is, how do I get back that xml variable? Isn't there a method available within the ASIHTTPRequest library? I am using ASIFormDataRequest class not ASIHTTPRequest.
You have to print you variable in the php-file:
if($this->outMethod=="" || $this->outMethod=="POST") //Default to POST
{
echo $_xml;
}
A HTTPRequest (and the ASIFormDataRequest as well) isn't interested in any variables you declare in your *.php file. It only returns the string you actually print.