1
votes

Following the RKGist example app I've managed to get my API syncing with Core Data through RestKit.

This is just for one model with an association; I'm trying to add extra routes and just can't get it working.

AppDelegate.m

- (void)setupRestKit
{
    // ...
    RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[JGMappingProvider personMapping]
                                                                                            method:RKRequestMethodGET
                                                                                       pathPattern:@"people"
                                                                                           keyPath:@"response"
                                                                                       statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [objectManager addResponseDescriptor:responseDescriptor];



    responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[JGMappingProvider companyMapping]
                                                                      method:RKRequestMethodGET
                                                                 pathPattern:@"companies"
                                                                     keyPath:@"response"
                                                                 statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [objectManager addResponseDescriptor:responseDescriptor];


    // add some routes
    [[RKObjectManager sharedManager].router.routeSet addRoute:[RKRoute routeWithName:@"approve_company" pathPattern:@"companies/:companyId/approve" method:RKRequestMethodPUT]];

    ...
}

JGMappingProvider.m

+ (RKMapping *)companyMapping
{
    RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Company"
                                                          inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];

    [mapping addAttributeMappingsFromDictionary:@{
                                                         @"id":             @"companyId",
                                                         @"name":           @"name",
                                                         @"looking_for":    @"lookingFor",
                                                         @"location":       @"location",
                                                         @"updated_at":     @"updatedAt",
                                                         @"created_at":     @"createdAt"}];

    mapping.identificationAttributes = @[ @"companyId" ];

    [mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"person" toKeyPath:@"person" withMapping:[self personMapping]]];

    return mapping;

}

+ (RKMapping *)personMapping
{
    RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Person"
                                                         inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];


    [mapping addAttributeMappingsFromDictionary:@{
                                                        @"name":           @"name",
                                                        @"nickname":       @"nickname",
                                                        @"id":             @"personId",
                                                        @"email":          @"email"}];

    mapping.identificationAttributes = @[ @"personId" ];

    return mapping;
}

@end

This all works fine. However, when I try to add some extra routes…

ViewController.m

- (void)approve
{
    NSMutableURLRequest *request = [[RKObjectManager sharedManager] requestWithPathForRouteNamed:@"approve_company" object:_company parameters:nil];
    [self sendRequestWithSharedManager:request];
}

- (void)reject
{
    NSMutableURLRequest *request = [[RKObjectManager sharedManager] requestWithPathForRouteNamed:@"reject_company" object:_company parameters:nil];
    [self sendRequestWithSharedManager:request];
}

- (void)sendRequestWithSharedManager:(NSMutableURLRequest *)request {
    RKObjectRequestOperation* operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:(NSURLRequest *)request success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        NSLog(@"success!");
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        NSLog(@"%@", [error description]);
    }];


    operation.targetObject = nil; // this was suggested in a tutorial, has no affect

    NSLog(@"Requested %@", [operation.HTTPRequestOperation.request.URL description]); // this is the correct URL, all the time

    [[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation];
}

Most of the time it fails. Specifically, it seems to be failing for the first 2 requests — not hitting my server at all (I have some breakpoints on the server side to debug), but on the third request it works perfectly.

I'm baffled - if it works the third time then presumably something is set up right?

Here are the logs - they're a bit of a mess & I don't really know what I'm looking for. https://gist.github.com/jongd/d28b5f58a901270999f2/raw/839f1b529538ab1814a49350c33b0057cb5b98fc/logger.txt

Ahah - turns out it /was/ hitting my server, the logs were just wrong. Schoolboy error - sorry about that.

I still have the problem of my response descriptor not being set up properly - can I get some help with this?

[RKResponseDescriptor responseDescriptorWithMapping:[JGMappingProvider companyMapping]
                                             method:RKRequestMethodPUT
                                        pathPattern:@"companies/:companyId/approve"
                                            keyPath:@"response"
                                        statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

I can't seem to get the pathPattern to match up - ideally I'd have a wildcard that matches companies/:companyId/approve & companies/:companyId/reject but I can't see how to do that in the docs.

Apologies for the stupid questions!

EDIT: done! I was using responseDescriptorWithMapping: method: pathPattern: keyPath: statusCodes: - got it all working with the (deprecated?) responseDescriptorWithMapping: pathPattern: keyPath: statusCodes:

2

2 Answers

1
votes

First, are you sure you are not hitting the server - according to your logs it seems to reach the server:

'http://localhost:1313/api/1/companies/19/approve' (200 OK / 0 objects) [request=1.0492s mapping=0.0000s total=1.0514s]

There seems to be a problem with your second RKResponseDescriptor (the one for companies) not getting set correctly.

Could you try not to reuse the local variable responseDescriptor for creating and passing the second RKResponseDescriptor.

1
votes

I'm assuming your base URL is http://localhost:1313/api/1/.

All 3 of your requests have a URL: 'http://localhost:1313/api/1/companies/19/approve' RestKit logs "No response descriptors match the response loaded.". This means that out of all of your response descriptors, none have a path pattern which matches companies/19/approve. You need one which does.

The 3rd request does not succeed with any mapping... All 3 requests did hit the server though (and you can see the response content in the log.

Bear in mind that routes are for request path creation. Generally by property injection (hence the path companies/19/approve where the 19 is injected).

Response descriptors are linked to routes only by virtue that they use the request path pattern. Whenever you make a request, you need a response descriptor which will match against that request. (response descriptor path pattern of nil matches everything).