I am saving 4 different tokens on Server using Restkit Coredata.
using response descriptor.
RKResponseDescriptor *tokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:instagramToken method:RKRequestMethodGET pathPattern:#"register/token" keyPath:#"data" statusCodes:statusCodes];
// And I'm calling it this way.
[[RKObjectManager sharedManager] getObjectsAtPath:#"register/token" parameters:params success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
it is storing very well and I can access it in coredata as well. but the problem is,
If I save 1 token on server and map the response all good no issue in that. But when I save other token on Server the new response get mapped in coredata and over-right the old response.
I want to keep all the responses in coredata.
Please help on this.
The server needs to return a unique identity for each token so you know which is which. You need an attribute in your model to store that and you need to add that to the mapping and set it as the mapping identification attribute. Finally you need to connect your RK managed object store with an object cache so that it can search for duplicates to update (instead of always creating new instances).
Related
I have the following JSON coming from my server...
{"Devices": [
{
"uuid": "d9084134-d5f7-43a3-9613-7faa769a822a",
"label": "",
"location": "a13d45f4-5ce0-48e3-bc3f-4076bb007037",
"capability": 0
},
{
"uuid": "a4ee0d3f-4a6a-4c61-81bd-3dfa9ab19e85",
"label": "",
"location": "a13d45f4-5ce0-48e3-bc3f-4076bb007037",
"capability": 3
}
]}
I'm trying to map this properly but I'm struggling with it... I have the following mappings setup...
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:#"Device" inManagedObjectStore:managedObjectStore];
[entityMapping setIdentificationAttributes:[NSArray arrayWithObject:#"uuid"]];
[entityMapping addAttributeMappingsFromDictionary:#{
#"uuid": #"uuid",
#"label": #"label",
#"location": #"location",
#"capability": #"capability"
}];
// GET
RKRequestDescriptor *getRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[entityMapping inverseMapping] objectClass:[Device class] rootKeyPath:#"Device" method:RKRequestMethodGET];
[[RKObjectManager sharedManager] addRequestDescriptor:getRequestDescriptor];
[[RKObjectManager sharedManager].router.routeSet addRoute:[RKRoute routeWithClass:[Device class] pathPattern:#"Devices" method:RKRequestMethodGET]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping method:RKRequestMethodGET pathPattern:#"Devices" keyPath:#"Devices" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
I have my keyPath set to "devices" which I would've thought would work. But RestKit isn't understanding it.
I'm using the following to get the objects from my server...
[[RKObjectManager sharedManager] getObjectsAtPath:#"Devices" parameters:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:#"%d", clientID], #"clientId", #"topic", #"forTopic", nil] success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
...
}... // Abbreviated for brevity.
So I believe my path "Devices" is correct for the pathPattern of "Devices". Are the parameters messing it up? I've had parameters before and it's always worked without having to specify anything in the mapping.
I'm using RestKit 0.27.1 currently.
UPDATE - Fixed JSON
I fixed the JSON as mentioned by Mahendra GP. So this is now a proper array. The RestKit log is now showing the JSON coming through in the trace log. However it still can't identify which object it is (Device).
Snippet of the log...
...and targetObject: (null)
2018-03-09 02:44:05.603734-0700 MyTestApp[31576:6868006] D restkit.object_mapping:RKMapperOperation.m:440 Finished performing object mapping. Results: (null)
2018-03-09 02:44:05.605334-0700 MyTestApp[31576:6868006] E restkit.network:RKObjectRequestOperation.m:172 GET 'http://[MY_IP]:8080/Devices?clientId=5199&forTopic=topic' (200 OK / 0 objects) [request=2.6488s mapping=0.0000s total=2.6633s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No response descriptors match the response loaded."
I finally figured out my issue by fluke trial and error. I wasn't able to find any specific posts on SO or over on RestKit's site. Therefore I thought I would post the, simple, solution to the problem here.
I kept getting errors that none of my response descriptors matched any of the key paths. I thought it had to do with the parameters I was passing to the GET as it would show that in the error trying to compare it to just the Devices path that the response descriptor was setup with. However this turned out not to be the issue at all.
The issue was with my RKResponseDescriptor setup. I originally had...
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping method:RKRequestMethodGET pathPattern:#"Devices" keyPath:#"Devices" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
The solution here is the "pathPattern". This needed to be set to nil.
I've been using RestKit for many many years. Prior to the 0.2x releases. I remembered something about RestKit being able to identify an entity and it's multiple just by pluralizing it. I finally thought that perhaps because I was specifying it in the pathPattern it was causing the issue. So once I eventually set that to nil it finally started working. I actually think the reason why was that setting it to nil was like setting it it to a wildcard for any pathPattern since my path actually had parameters tagged onto them.
However in another use case I had I did specify the pathPattern but instead of it being the plural of the mapped entity it was something different. So instead of Devices I had something like DeviceForUser. So there seems to be a problem when specifying the plural of the entity in the pathPattern. Especially if using parameters in the getObjectsAtPath call.
So for clarity, all of the code above is the same. It just needs this change...
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping method:RKRequestMethodGET pathPattern:nil keyPath:#"Devices" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
I hope this helps anyone else who might run into this.
I have configured RestKit successfully so I can send out POST messages to the device I'm working with.
I have confirmed that when I use Chrome's Postman that the format of the message is correct.
I need to send......
id=87654321&content={"ts":1396215675,"payload":{"ssid_pass":"blah"}}&t=12345678
So in Chrome's postman, it goes out correct. But when I use RestKit postObject
[manager postObject:self path:#"/tom" parameters:#{#"id" : K_IDVALUE, #"content": myPayload, #"t":K_TVALUE, } success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Successful Post!");
The order the device sees is wrong. It sees
content={"ts":1396215675,"payload":{"ssid_pass":"blah"}}&id=87654321&t=12345678
The device really wants the content to be between the id and t tags of the POST request. Is there a way to force RestKit to take the parameters as is? It appears that the message is being alphabetized (which I assume is happening at serialization).
Is there a way to force RestKit to take the parameters as is?
What you are passing into RestiKit:
#{#"id" : K_IDVALUE, … }
is a NSDictionary, which has no concept of ordering of its elements.
Your only chance then is that RestKit is using the mapping you specify to determine the order of the keys. I cannot check now into RestKit sources to confirm this hypothesis, but you could just try it out (or simply verify what is your mapping current ordering).
Let's say that in response to a PUT request:
[[RKObjectManager sharedManager]
putObject:nil
path:#"/api/users/add-user"
parameters:dictionary
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
NSLog(#"Success");
}
failure:^(RKObjectRequestOperation *operation, NSError *error){
NSLog(#"Failure");
}
];
I get a "JSON" of unknown structure. I don't know what and how many keys to expect, but the values are all strings. How do I map it to a NSDictionary *object?
You can use a REST client to see the response and the structure of the JSON response, and create a corresponding model to map it against. Or if this is something that is not a consistent model, you can use NSJSONSerialization to parse the JSON into a KV pair, and your variable of interest in 'mappingResult'.
And you might want to look in AFNetworking 2.0. It works very well with your REST calls and parsing your JSON.
http://nshipster.com/afnetworking-2/
If the JSON response has an unknown structure then you either shouldn't be using RestKit (just use NSJSONSerialization and handle everything yourself) or you will need to use an RKDynamicMapping so that you can analyse the incoming data and decide what mapping to create (on-the-fly) and return to action the processing.
I am using the postObject and putObject functions of restKit. I need to extract some info from the payload and put it in the header before sending it out.. any suggestions on how I can do that?
ex:
[[RKObjectManager sharedManager] postObject:object path:OBJECT parameters:nil success:success failure:failure];
I will probably have to do something like
// Create Payload for this request
// update header accordingly
// call postObject
I would like to avoid throwing away existing code..
I was able to do this by using all the params that I was passing before making the RK request.
The API I'm developing against requires me to present an authentication token in a custom HTTP header. This token expires every few minutes, and could happen while the user is still within the app as long as they have been idle long enough. When the token has expired I receive a 403 response but I only find out after attempting a request.
What's the best way to get RestKit to automatically reauthenticate and retry the request so I don't have to put in this logic everywhere I make a request? Responses to similar questions have suggested using the RKRequestDelegate protocol or the RKObjectLoaderDelegate protocol but unfortunately these are no longer part of RestKit (as of 0.20).
Any idea what the "correct" approach should be now? Should I be subclassing RKObjectManager and tacking on a retry to each of the request operations or should I provide a custom HTTPOperation or HTTPClient class or is there some better approach altogether? Thanks!
Catch it in Failure block , and check for the status code and re-do the authentication
RKObjectRequestOperation *requestOp = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[getObjResp]];
[requestOp setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
....
}
} failure:^(RKObjectRequestOperation *operation, NSError *error){
// Here your status code check
// Here your retry-code
}