So I'm trying to do a post request with an array of JSON parameters sent to a server, here's the code for that
for(USER_ACTIONS *ua in [USER_ACTIONS listRegisterdActions]){
//Create a single JSON object here
[array addObject:jsonString];
}
NSString *dataString = [NSString stringWithFormat:#"[%#]",array.count ?
NSData* data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[#"data"] = data;
[self POST:#"?cmd=log" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];
This works with a single JSON object, but once there are more of them I get the following exception
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (NSConcreteMutableData)'
It's out of the question to do this with a multiple post requests so I need a way to do this with one, my search results on this have not gotten any clear results on how to do this with AFNetworking 2.x so I'd appreciate some pointers on where to go with this.
AFNetworking can automatically change paramter in NSDictionary to JSON.
change your manager's property requestSerializer to AFJSONRequestSerializer the default value is AFHTTPRequestSerializer
AFJSONRequestSerializer is a subclass of AFHTTPRequestSerializer that encodes parameters as JSON using NSJSONSerialization, setting the Content-Type of the encoded request to application/json.
For some reason just using the AFHTTPSessionManager Post function with the constructingBodyWithBlock parameter actually works for some reason. No idea why this is needed because there isn't actually anything in that block, if anyone could tell me why it would be nice.
[self POST:#"?cmd=log" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
//For some reason the request won't work unless this block is included in the function as well, even though nothing is actually done in it
} success:^(NSURLSessionDataTask *task, id responseObject) {
//Success code here
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];
Related
I am working on an app where I have AFNetworking fetching JSON requests from the my server. Now JSON is dynamically created based upon the POST variables I send from my app.
I was wondering when I get the following error message
JSON text did not start with array or object and option to allow fragments not set.
Is there a way to adapt my code so that I can actually see in the logger what the returned JSON request looks like. I have a feeling that there is a warning popping up in my PHP that is throwing off the JSON but I am not sure what it is.
Here is my code, it would make it so much easier if I could lets say NSLog the body content.
[manager POST:#"__MY__URL__" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
} progress:nil success:^(NSURLSessionDataTask *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
if([[responseObject objectForKey:#"state"] isEqualToString:#"success"]){
//[self performSegueWithIdentifier:#"client_choose_ad" sender:self];
}else {
[self alertError:#"Unable To Create Advert" alertMessage:[responseObject objectForKey:#"message"]];
}
} failure:^(NSURLSessionDataTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Maybe printing the raw data of the request is what you are looking for.
How to print AFNetworking request as RAW data
I was wondering, is there a file format that allows you to store keys and values, and some api that lets you read said file from a web server into a NSDictionary easily? I'm just trying to store 5 or so values associated with keys in a file on the web, so looking for something simple.
I know how to read a simple text file into an NSString, but I was wondering if there is something that lets me do what I described above easily / more efficiently without having to manually prepare the file myself and then write the code to tokenize it, etc.
The file format you need is json. The API you need is AFNetworking. Here is the sample which connect to a server and parse that json to NSDictionary.
//send son info to server
NSDictionary* json = #{
kUserTokenKey : [SOLUser currentUser].token,
kMarkerUserMarkPayIDKey : markerUserMark.objectID,
kCardMarkerPayIDKey : card.objectID,
kCardZipCodeKey: zipCode
};
//create a request url
NSString* requestURL = [NSString stringWithFormat:#"%#%#",kSOLServicesURL,kSOLServicesMarkerPay];
//AFNetworking block to call server api
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager POST:requestURL parameters:json success:^(NSURLSessionDataTask *task, id responseObject) {
[manager invalidateSessionCancelingTasks:YES];
//Recieving object from server and pass to json
NSDictionary* obj = responseObject;
if ([obj[kAPIStatusKey] isEqualToString:kAPIStatusSuccessKey]) {
if (completion) completion(nil);
} else {
NSError* error = [NSError errorWithMessage:obj[kAPIDataKey] code:0];
if (completion) completion(error);
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[manager invalidateSessionCancelingTasks:YES];
LBLog(#"Error: %#", error);
if (completion) completion(error);
}];
I'm trying to use AFNetworking to call the parse.com REST API.
GET-Requests are working quite well so far. But when it comes to object creation I have a problem creating relations (pointers to object-ids) between two parse objects.
What I've tried so far:
NSString* parameterString = [NSString stringWithFormat:#"{\"__op\":\"AddRelation\",\"objects\":[{\"__type\":\"Pointer\",\"className\":\"MyClass\",\"objectId\":\"%#\"}]}", myClassObjectId];
NSDictionary *parameters = #{#"myClass": parameterString};
[self.manager POST:url parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { ... }];
Creating objects without pointers works well too. I think the error is related to my parameterString syntax:
Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: bad request (400)","code":111,"error":"invalid type for key myClass, expected *MyClass, but got string"
Any ideas? Thank you ;)
I got the answer, finally:
NSDictionary *params = #{#"myClass":#{#"__type":#"Pointer", #"className":#"MyClass", #"objectId":[foobar objectID]}};
[self.manager POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) { ... }];
so... just plain JSON.
Using the Postman extension for Chrome I can successfully POST some JSON. Using Charles to inspect the request, I see that the request data is as follows:
{
"query": {
"term": {
"user_id": "12345"
}
}
}
When I try to construct this same request using AFNetworking 2.4.1, I can see that the data is formatted as:
query[term][user_id]=12345
The server of course returns an error.
What part of the POST request am I getting wrong?
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"query":#{#"term":#{#"user_id":#"12345"}}};
[manager POST:#"http://someURL" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"SUCCESS %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"FAIL: %#", error);
}];
The short answer is:
manager.requestSerializer = [AFJSONRequestSerializer serializer];
From the documentation:
Requests created with requestWithMethod:URLString:parameters: &
multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:
are constructed with a set of default headers using a parameter
serialization specified by this property. By default, this is set to
an instance of AFHTTPRequestSerializer, which serializes query
string parameters for GET, HEAD, and DELETE requests, or
otherwise URL-form-encodes HTTP message bodies.
After trying nearly every response on the subject, I've come up without a working answer to my problem.
The problem: So I've implemented the uploading portion of my app using AFNetworking 2.0.3 after porting from AFNetworking 1.3:
-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock {
NSData* uploadFile = nil;
if ([params objectForKey:#"file"]) {
uploadFile = (NSData*)[params objectForKey:#"file"];
[params removeObjectForKey:#"file"];
}
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://54.204.17.38"]];
manager.responseSerializer = [AFJSONResponseSerializer serilizer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/json"];
AFHTTPRequestOperation *apiRequest = [manager POST:#"/API" parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
if (uploadFile) {
[formData appendPartWithFileData:uploadFile name:#"file" fileName:#"photo.jpg" mimeType:#"image/jpeg"];
}
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
completionBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
[apiRequest start];
}
The error I get when using this code is "Request failed: unacceptable content-type: text/html" I know you might be wondering if the server is responding with proper JSON, and I have every reason to think it is after inspecting the response headers in my browser that say 'MIME type: application/json'. Also, I am using 'header('Content-type: application/json')' at the top of my API as well (PHP API). Now, if I change the serialization type to 'AFHTTPResponseSerializer' instead of 'AFJSONResponseSerializer', it will not spit out the JSON error, but it will give me a different error (a random unrecognized selector error).
Any thoughts on why I cannot seem to get a JSON response out of this method?
You can set the AFHTTPSessionManager to accept any MIME Type:
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
Got it! So, turns out, unknowingly, although my API was returning valid JSON, matter examining the header response logged on the Xcode side of things (thru NSLog(#"Error: %#", error);), it was actually returning text/HTML because it wasn't actually hitting the correct file, it was getting re-routed by a header somewhere. After explicitly stating the API path to be /API/index.php and not just /API, it started returning the valid JSON! Next, after making sure the response was properly JSON serialized (using requestManager.responseSerializer = [AFJSONResponseSerializer serializer];), the app worked!
Hopefully this helps someone who was having the same issue :)