How to specify Restkit object manager to perform a POST - objective-c

I am trying to send a POST request using ios Restkit. I can perform a GET, but cannot find how to send a POST.
My current code looks like the following:
RKURL *URL = [RKURL URLWithBaseURL:[objectManager baseURL] resourcePath:#"/users/sign_in.json" queryParameters:params];
[objectManager loadObjectsAtResourcePath:[NSString stringWithFormat:#"%#?%#", [URL resourcePath], [URL query]] delegate:self];
Apparently, this performs a GET. Any idea what I should add to make it a POST?
Thanks!

You can configure your RKRequest with:
[request setMethod:RKRequestMethodPOST];

To answer your question (regardless of the above discussion) you can do the following:
[objectManager loadObjectsAtResourcePath: #"path" usingBlock: ^(RKObjectLoader *loader) {
loader.HTTPMethod = RKRequestMethodPOST;
}];

Related

AFNetworking JSON parsing - fails of unknown reason

im trying to parse some JSON. for simplicity ill explain using the default example at github:
when running:
NSURL *url = [NSURL URLWithString:#"http://httpbin.org/ip"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request success:^(
NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"IP Address: %#", [JSON valueForKeyPath:#"origin"]);
} failure:nil];
[operation start];
i get the correct output logged. however, when i copy the example's content (which is basically 1 element) to a txt or html file (so URLWithString gets #"http:// my server address /file.txt"), putting it on my testing server and trying to prase from there, i get no output. what is wrong with this? thanks for your time!
(note: if i go to http:// my server address /file.txt i can see the contents there clearly so that's not the problem)
edit: as suggested, the content is:
"{
"origin": "10.44.119.100"
}"
Your problem probably has something to do with the fact that you're serving content as a text file (.txt) rather than as JSON (Content-Type: application.json / .json extension). AFNetworking is strict about HTTP standards in order to guard against unexpected behavior. Either set the correct Content-Type header on your server, or (as a hack) do AFJSONRequestOperation +addAcceptableContentTypes: adding text/plain.
As a meta note: when asking a question on Stack Overflow, specifics matter. If you had posted the error you were seeing in the console, it would be much easier to determine what the problem was. Likewise, approximate code is not actual code; if you have a problem, be specific about exactly what's going on. Details matter.
You should encode the json data first and then write it into the text file and when you are reading the data from file... decode the data first...
EDIT:
replace JSON operation with simple http and check if you are able to get data from there...
and if you are then JSONOperation basically is seeking for json response which is not in text file... i guess
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setUploadProgressBlock:^(NSInteger bytesWritten,long long totalBytesWritten,long long totalBytesExpectedToWrite)
{
NSLog(#"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite);
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *str = [[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#" Success %#",str);
// id response = AFJSONDecode(responseObject, nil);
[self requestSucceed:response];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"error: %#", operation.responseString);
}];

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];

Mapping RestKit Post Response

I am posting to a uri using RestKit
NSString* path = [NSString stringWithFormat:#"myPathHere"];
NSDictionary *params = [NSDictionary dictionaryWithKeysAndObjects:#"rating",[rating stringValue], nil];
[[RKObjectManager sharedManager].client post:path params:params delegate:self];
The server will respond with an updated version of my managedObject "Item".
How do I go about mapping this item. Do I use the following delegate method?
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response{}
I know that from here I can get the response JSON value but how do I change that into the mapped object?
Any help is much appreciated.
Thanks!
When I've needed to map my server objects I make the request like this:
[[RKObjectManager sharedManager]
loadObjectsAtResourcePath:[qualifiedResourceURL
appendQueryParams:params]
delegate:self
];
and then the object comes back in this method:
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
I then post the updated object with the Notification Manager
[[NSNotificationCenter defaultCenter] postNotificationName:GotFotosInRegion_Fotos_Array_Response object:objects];
The best documentation is at https://github.com/RestKit/RestKit/blob/master/Docs/Object%20Mapping.md

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