I am trying to produce a request using afnetworking in objective c, however, it seems like the hardware that I am trying to connect to only applies requests when the parameters of the request are in a specific order. So I am wondering if there is a way to make the request so that the parameters are in a specific order. (As just doing it normally seems to jumble the sequence of the params up)
Here's my code:
NSDictionary *params = #{
#"param1" : #"bla",
#"param2" : #"bla2",
#"param3" : #"bla3"
};
[requestManager GET:#"somewhere" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
DLog(#"Success!");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DLog(#"Fail: %#", error);
}];
It actually goes to success every time, its just that the request I had applied would be practically ignored.
The actual request body becomes something like "param3=bla3¶m1=bla1¶m2=bla2 etc which would be ignored as it seems.
You can't do that using the request manager in the way you currently are.
Instead, you would need to create the parameter list yourself, and then create a request from that. Then you could use AFN to handle the request transmission and response.
Note that the server shouldn't require a specific order and that this should be changed if possible. Note also that the dictionary of parameters has no order (even though you add the keys in a set order).
Keeping the order of the parameters have a great impact on server performance. This sounds silly at first, but just think about GET requests which contain the query string as part of the URL. Web servers can cache the response for the given URL. If you mess with the order of the parameters, the cache won't be as effective as it could be.
The case is even worse if you call an API from different platforms (iOS, Android, Web) and they all reorder the params, which means that the same content will be found on 3 different cache keys.
Keeping the order is a performance issue at the first place.
Related
I have a web_custom_request method that needs to handle dynamic item data
web_custom_request("create",
"URL=someurl\create",
"Method=POST",
"Resource=0",
"RecContentType=application/json",
"Referer=someurl",
"Snapshot=t6.inf",
"Mode=HTML",
"EncType=application/json",
"Body={\"actions\":{\"name\":\"value\"}}"
LAST);
To address the dynamic name-value pair parameters that come into play, I had built a bufferthat would hold the Body string. I have used correlation and looping to achieve that. Code towards the end of building this buffer looks like this
lr_param_sprintf("s_buffer", "\\\"actions\\\":{%s}",paramStr);
lr_output_message("Final Actions string is %s", lr_eval_string("{s_buffer}"));
Output for above lr_output_message is
Final Actions string is \"actions\":{\"name\":\"value\"}
I replaced Body parameter in web_custom_request with the buffer I had built
web_custom_request("create",
"URL=someurl\create",
"Method=POST",
"Resource=0",
"RecContentType=application/json",
"Referer=someurl",
"Snapshot=t6.inf",
"Mode=HTML",
"EncType=application/json",
"Body={s_buffer}"
LAST);
I receive a HTTP Status-Code=400 (Bad Request) indicating the format of web_custom_request is wrong. I would highly appreciate if someone could help me with the Body parameter so that the web_custom_request embraces it like the way it should.
Record it three times. First two with the same login session. The third with another one. You likely have something that is going to change based upon data which is not being handled in the body appropriately.
I'm fairly new to Restkit but so far its worked pretty well for me using version 0.20.3 for most of my networking needs.
Im consuming a json based API written in c# using WCF webhttp bindings, it is worth mentioning at this point that I have absolutely no control of this API and cannot change the format of the returned json and I need to work with what I have.
The problem is that when the API returns a simple type like int, double or string as the response the json response is completely bare as below..
string response
"hello world"
int response
2342524
Both of these example responses have a content type of application/json
Ive tried to consume an API endpoint with restkit that gets a count of customer orders by the customer number.
The code for the request is as follows and Im expecting an NSNumber as the response but its generating an error as its a raw unwrapped type and I cant provide a mapping for this.
[manager getObject:nil
path:#"/service/http/CountOrders?CustomerId=324534413"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
RKLogInfo(#"order count: %#",mappingResult);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
}];
And the error I'm getting back is
restkit.network:RKResponseMapperOperation.m:317 Failed to parse response data: Loaded an unprocessable response (200) with content type 'application/json'
restkit.network:RKObjectRequestOperation.m:213 GET 'http://CUSTOMERDOMAIN/service/http/CountOrders?CustomerId=324534413'
(200 OK / 0 objects)
[request=0.2263s mapping=0.0000s total=0.2386s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1017 "Loaded an unprocessable response (200) with content type 'application/json'"
UserInfo=0x8e1a660 {NSErrorFailingURLKey=http://CUSTOMERDOMAIN/service/http/CountOrders?CustomerId=324534413, NSUnderlyingError=0x8e1b1a0
"The operation couldn’t be completed. (Cocoa error 3840.)",
NSLocalizedDescription=Loaded an unprocessable response (200) with content type 'application/json'}
hj
Is there any way of parsing the the response to an NSNumber to cover this edge case?
Im thinking a custom deserialization handler might be the way to go if thats at all possible but as I said I'm new to restkit and am basically looking for a push in the right direction.
A custom serializer could work, but a simple approach is probably to skip RestKit for the requests with 'simple' responses and use the underlying AFNetworking classes instead. Then you don't need to worry about serialization and you can just quickly coerce the response value.
I am fetching an object from the persistentStoreManagedObjectContext and showing some of its value to my user within a UIView. That object, let's call it Book has an Author relationship. Whenever I am about to display that book, I check if the author is set or not. If it's not set, I do:
[[RKObjectManager sharedManager] getObjectsAtPath:[NSString stringWithFormat:#"/api/rest/userprofiles/%#/",_currentBook.authorID] parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {..}
Within the success callback, I want to do a:
_currentBook.author = mappingResult.firstObject;
if (![_currentBook.managedObjectContext saveToPersistentStore:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
However, I can't do _currentBook.author = mappingResult.firstObject; because I get:
Illegal attempt to establish a relationship between objects in different contexts
However, I know that this newly fetched Author is saved within the persistentStoreCoordinator, because I configured my RestKit to do so (or it's by default, I can't remember). So I don't want to create that object AGAIN, I would just want to get it's value within my currentContext which is persistentStoreManagedObjectContext. Do I have to use a NSFetchedResultsController just for that?
Edit
I already have a connection in the book to connect to the author, via the authorID, which I send back at the same time as getting the Book object from my server. However, it might be the case that the Author Object is not fetched yet, hence I keep that ID.
[bookMapping addConnectionForRelationship:#"author" connectedBy:#{ #"authorID": #"identifier" }];
However, even after that author is fetched, book.author is set to null, unless I REFETCH once again in the persistent storage.
You should get RestKit to connect the relationship using foreign key mapping based on the author id. That way all of the updates are made at the same time, in the same context, and saved before the mapping result is returned.
I'm working on a project that requires downloading a list of users from a server —JSON data created from a PHP script that reads a MySQL database— and I would like to inform the user of the progress of the request but onDownloadProgressChanged: never gets called when sending a GET request through operationWithPath:params:httpMethod:ssl: and I don't know if that is an intended behavior or not.
MKNetworkOperation *op = [self operationWithPath:kSPGetUserListPath params:nil httpMethod:#"GET" ssl:YES];
Should onDownloadProgressChanged: be called when I send a GET request with operationWithPath:params:httpMethod:ssl: or is it only called when downloading a file using addDownloadStream:?
Whenever I send a POST request with a file attached through addData: method of MKNetworkOperation the onUploadProgressChanged: method get called accordingly.
Thank you!!!
I had the same problem because missed something like the following MKNetworkEngine initializing in the main class:
self.sampleDownloader = [[ExampleDownloader alloc] initWithHostName:nil customHeaderFields:nil];
I'm using the GoogleDrive Objective-C SDK, and I'm running into an issue. I want to build up a path -> ID mapping structure, so I ask Drive for a list of all of a users files. Normally this works fine. But, in cases where users have very large amounts of files, the server returns an internal error. I can fix this by setting the maxResults property on my GTLQueryDrive to a lower number. When I do that, everything works as expected, EXCEPT that the nextPageToken (and nextLink) property of the GTLDriveFileList is nil. I believe I need this nextPageToken to continue grabbing file information. I have tried setting the fields property on my query to nil, to a string that includes nextPageToken, and to a string that does not include nextPageToken. The nextPageToken property appears to be nil in all cases. Is there something I am missing? Thanks!
Adding answer based on comment chain.
Here's a little sample that you can experiment with.
driveService.shouldFetchNextPages = YES;
GTLQueryDrive *query = [GTLQueryDrive queryForFilesList];
query.maxResults = 5;
// queryTicket can be used to track the status of the request.
[driveService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket, GTLDriveFileList *files,
NSError *error) {
if (files) {
NSLog(#"Have response %#", files.items);
NSLog(#"Token %#", files.nextPageToken);
NSLog(#"Count %d", files.items.count);
}
}];
With shouldFetchNextPages set to YES, the result will not contain a nextPageToken. Instead, assuming you have more than 5 files (based on maxResults) you'll still get the full list, along with a message in the log file that will look something along the lines of:
Executing drive.files.list required fetching 4 pages; use a query with a larger maxResults for faster results
If you set shouldFetchNextPages to NO, the result will be capped at 5 results in this case, and nextPageToken will have a valid token for getting the next page in the result set.