Search code examples
iosobjective-crestkitjson-rpc

Map resources depending on the request's parameters


My application is using the protocol JSON-RPC to communicate with the backend. What I basically want to to do is to fetch objects and store them directly in Core Data. I have multiple types of entities. Let's take for example Events and Podcasts. I am fetching them by hitting an API at the same endpoint with a POST request for both of the entities. The only thing that changes are the params:

For the Events:

{
    id = 0;
    jsonrpc = "2.0";
    method = "Events.Event.list";
    params =     {
        location =         {
            type = token;
            value = haHssQWR0V8d;
        };
        sessionId = v1oCLGlfxIvqYxhaHssQWR0V8dkFeS1JUqlF;
        week = "2014_42";
    };
}

For the Podcasts:

{
    id = 1;
    jsonrpc = "2.0";
    method = "Podcasts.Podcast.list";
    params =     {
        sessionId = v1oCLGlfxIvqYxhaHssQWR0V8dkFeS1JUqlF;
    };
}

I am currently creating response descriptors for every entity mapping like this.

+ (void)configureAllObjectsMapping
{
    [self mapEvent];
    [self mapPodcast];
}

+ (RKEntityMapping *)mapEvent
{
    if (_eventMapping) {
        return _eventMapping;
    }

    _eventMapping = [self mappingForClass:[Event class]];
    _eventMapping.identificationAttributes = @[CoreDataPrimaryKey];
    [_eventMapping addAttributeMappingsFromDictionary:@{
                                                        @"token":@"token",
                                                        @"name":@"name",
                                                        @"urlWeb":@"urlWeb",
                                                        @"urlImage":@"urlImage",
                                                        @"startsAt":@"startsAt",
                                                        @"endsAt":@"endsAt",
                                                        @"costs":@"costs",
                                                        @"description":@"desc",
                                                        @"genres":@"genres",
                                                        @"artists.isSecret":@"hasSecretArtist",
                                                        @"hasGuestlist":@"hasGuestlist",
                                                        @"countGoings":@"countGoings"
                                                        }];

    [_eventMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"venue"
                                                                                  toKeyPath:@"venue"
                                                                                withMapping:[self mapVenue]]];

    [_eventMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"artists.data"
                                                                                  toKeyPath:@"artists"
                                                                                withMapping:[self mapArtist]]];

    RKResponseDescriptor *list = [RKResponseDescriptor responseDescriptorWithMapping:_eventMapping
                                                                              method:RKRequestMethodPOST
                                                                         pathPattern:nil
                                                                             keyPath:@"result.data"
                                                                         statusCodes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(RKStatusCodeClassSuccessful, 104)]];

    [[APIManager sharedInstance].manager addResponseDescriptor:list];

    return _eventMapping;
}

+ (RKEntityMapping *)mapPodcast
{
    if (_podcastMapping) {
        return _podcastMapping;
    }

    _podcastMapping = [self mappingForClass:[Podcast class]];
    _podcastMapping.identificationAttributes = @[CoreDataPrimaryKey];
    [_podcastMapping addAttributeMappingsFromDictionary:@{
                                                        @"token":@"token",
                                                        @"name":@"name",
                                                        @"urlWeb":@"urlWeb",
                                                        @"urlImage":@"urlImage",
                                                        @"description":@"desc",
                                                        @"duration":@"duration",
                                                        @"playCount":@"playCount"
                                                        }];

    RKResponseDescriptor *list = [RKResponseDescriptor responseDescriptorWithMapping:_podcastMapping
                                                                              method:RKRequestMethodPOST
                                                                         pathPattern:nil
                                                                             keyPath:@"result.data"
                                                                         statusCodes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(RKStatusCodeClassSuccessful, 104)]];

    [[APIManager sharedInstance].manager addResponseDescriptor:list];

    return _podcastMapping;
}

The problem is that the response descriptors for both the Podcast and Event entities are the same since the pathPattern is nil.

Therefore everything I receive from the backend is currently considered to be a Podcast since the mapPodcast method is called after the mapEvent method.

Does anyone know a way to differentiate the two responses and map each request's response to the right entity?

UPDATE: Response

This is the kind of response I get for my resources:

Event

{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "count": 1,
    "data": [
      {
        "token": "YAXDMJG17GRO",
        "event_name": "Klubnacht | Fachwerk Nacht",
        ...
      }
    ]
  }
}

Podcast

{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "count": 1,
    "data": [
      {
        "token": "G17GROYAXDMJ",
        "podcast_name": "Podcast #19",
        ...
      }
    ]
  }
}

So there is not event anything that can differentiate them, except maybe some parameters name.


Solution

  • Your only easy solution is to use a dynamic mapping to inspect the data in the response and choose the correct mapping (so you would have a single response descriptor pointing to this dynamic mapping).

    You can use parameters during mapping via the @metadata, but this won't help you in this case, it's really for differentiating different types of the same entity.

    At this point in time you can't use parameters for dynamic mapping choices or response descriptor choice. You could consider implementing this in RestKit, it isn't necessarily trivial.