Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple ResponseDescriptors seems to be confusing response object mapping #1719

Closed
devangmundhra opened this issue Dec 17, 2013 · 5 comments

Comments

@devangmundhra
Copy link

Consider a data model with two managed objects: ObjectA and ObjectB.

I have setup the routes as follows-

[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[ObjectA class] pathPattern:@"object_a/" method:RKRequestMethodPOST]];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[ObjectB class] pathPattern:@"object_b/" method:RKRequestMethodPOST]];

The request/response descriptors as setup as follows-

For ObjectA

[objectManager addRequestDescriptor:[RKRequestDescriptor
                                     requestDescriptorWithMapping:[ObjectA objectARequestMappingForRKPOST]
                                     objectClass:[ObjectA class]
                                     rootKeyPath:nil
                                     method:RKRequestMethodPOST]];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:[ObjectA objectAResponseMappingForRKPOST]
                                                                                  method:RKRequestMethodPOST
                                                                             pathPattern:nil
                                                                                 keyPath:nil
                                                                             statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

For ObjectB

[objectManager addRequestDescriptor:[RKRequestDescriptor
                                     requestDescriptorWithMapping:[ObjectB objectBRequestMappingForRKPOST]
                                     objectClass:[ObjectB class]
                                     rootKeyPath:nil
                                     method:RKRequestMethodPOST]];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:[ObjectB objectBResponseMappingForRKPOST]
                                                                                  method:RKRequestMethodPOST
                                                                             pathPattern:nil
                                                                                 keyPath:nil
                                                                             statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

Now the problem is, if I have only ObjectA's responseDescriptor added to the RKObjectManager, the response to ObjectA's POST response is deserialized and mapped correctly. However, if I add ObjectB's responseDescriptor to RKObjectManager as well, as shown above, then the response to ObjectA's POST response is not deserialized.

Is there a limitation in RestKit that only one responseDescriptor per method can be used in an ObjectManager?

@devangmundhra
Copy link
Author

I think the problem is in RKResponseMapperOperation.m.

In the init method, when getting the values for the responseDescriptors, we do-

self.matchingResponseDescriptors = [self buildMatchingResponseDescriptors];
self.responseMappingsDictionary = [self buildResponseMappingsDictionary];

buildMatchingResponseDescriptors uses the following method to match response descriptors which does not use the class of the object to match the response. It only uses the URL and the HTTPMethod (POST in this case).

- (BOOL)matchesResponse:(NSHTTPURLResponse *)response
{
    if (! [self matchesURL:response.URL]) return NO;

    if (self.statusCodes) {
        if (! [self.statusCodes containsIndex:response.statusCode]) {
            return NO;
        }
    }
    return YES;
}

Later, when the response descriptor for this response is to be selected, we use this in buildResponseMappingDictionary-

- (NSDictionary *)buildResponseMappingsDictionary
{
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    for (RKResponseDescriptor *responseDescriptor in self.matchingResponseDescriptors) {
        [dictionary setObject:responseDescriptor.mapping forKey:(responseDescriptor.keyPath ?: [NSNull null])];
    }
    return dictionary;
}

Thus we end up always using the last response descriptor that was queued to that ObjectManager for the HTTPMethod. In the example above, we use the ResponseDescriptor for ObjectB even though the POST was done for ObjectA.

@devangmundhra
Copy link
Author

I do understand I can use pathPattern to distinguish between response descriptors, but should there be another check of using the class object being mapped to for another round of filtering (which would have probably helped in a case like this). Or since the pathPatterns are nil here, should these be considered as misconfigured?

@blakewatters
Copy link
Member

This is a configuration error. RestKit can only use the response object to match the appropriate response descriptor. By specifying nil for the pathPattern and keyPath on both descriptors you have effectively created this situation. Your choices are either to:

  1. Use better constraints on the response descriptor to control the matching.
  2. Explicitly construct and configure the response descriptors on the object request operation.

The only framework change I would consider adding to this is raising an NSInternalInconsistencyException when you add overlapping descriptors to the manager.

@rwyland
Copy link

rwyland commented May 1, 2014

This is a pretty nasty bug, and I don't see how its a configuration error.

If I am clearly defining a descriptor of type POST, why should it EVER return the type GET, simply because it was the last to be queued for that pathPattern? Regardless of the keyPath being nil, this is just plain wrong.

@Mehly
Copy link

Mehly commented Jan 30, 2015

Any updates on this? I'm still having this issue.

Configuring two RKResponseDescriptors with the same pathPattern but two different RKRequestMethods (e.g. POST and GET) will result in the wrong RKResponseDescriptor being selected when the received data is being parsed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants