RESTKit: Two EndPoints POST, PUT, DELETE

2019-09-10 06:19发布

I have two EndPoints:

http://rest.domain.com/invite

http://rest.domain.com/template

Depending on what options the User selects, I need to able to PUT, POST, & Delete on both EndPoints.

Mapping for all three methods is slightly different. Mapping for each EndPoint is also different.

What's the best way to setup mappings so they are loaded once and can be used multiple times for each EndPoint depending upon what option (PUT, POST, or Delete) the User selects? I have to accomplish this on one storyboard Scene!

Currently, below is the code that I use when POSTing to the /invite EndPoint (it crashes after the first POST b/c I'm remapping):

- (void)sendInvite:(NSInteger)methodType
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    self.objectManager = [self getObjectManager];
    self.objectManager.managedObjectStore = appDelegate.managedObjectStore;
    RKEntityMapping *invitationMapping = [RKEntityMapping mappingForEntityForName:kInvite
                                                             inManagedObjectStore:self.objectManager.managedObjectStore];

    RKEntityMapping *activityMapping = [RKEntityMapping mappingForEntityForName:kActivity
                                                           inManagedObjectStore:self.objectManager.managedObjectStore];


    Invite *invitation;

    switch (methodType) {
        case POST:
        {
            invitationMapping = [RESTMappingProvider invitionPostMapping:invitationMapping];
            activityMapping =  [RESTMappingProvider activityPostMapping:activityMapping];
            [invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kActivitiesRelationship
                                                                                              toKeyPath:kActivitiesRelationship
                                                                                            withMapping:activityMapping]];

            invitation = [self inviteForMethod:POST]; //This method just assigns values to the attributes

            [self setupDescriptors:invitationMapping forKeyPath:kMeetupKeyPath descriptorClassIsTemplate:NO];
            [self.objectManager.HTTPClient  registerHTTPOperationClass:[AFHTTPRequestOperation class]];
            [self.objectManager.managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:NO];

            [self.objectManager postObject:invitation path:kMeetupKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
                [self removeDuplicateObjects];  //After removing relationship Dups, I save to persistent store

            } failure:^(RKObjectRequestOperation *operation, NSError *error) {
            }];

        }
            break;
        case PUTACCEPT:
        case PUTDECLINE:
        case PUTEDIT:
        {
            invitationMapping = [RESTMappingProvider invitionPutMapping:invitationMapping];
            activityMapping = [RESTMappingProvider activityPutMapping:activityMapping];
            [invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kActivitiesRelationship
                                                                                              toKeyPath:kActivitiesRelationship
                                                                                            withMapping:activityMapping]];

            invitation = [self inviteForMethod:methodType]; //This method just assigns values to the attributes

            [self setupDescriptors:invitationMapping forKeyPath:kMeetupKeyPath descriptorClassIsTemplate:NO];
            [self.objectManager.HTTPClient  registerHTTPOperationClass:[AFHTTPRequestOperation class]];

            [self.objectManager putObject:invitation path:kMeetupKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
            } failure:^(RKObjectRequestOperation *operation, NSError *error) {
                NSLog(@"Failure in PUT");
            }];
        }
            break;
    }
}

I do something similar for the Templates EndPoint

- (void)saveAsTemplate
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    self.objectManager = [self getObjectManager];
    self.objectManager.managedObjectStore = appDelegate.managedObjectStore;

    RKEntityMapping *invitationMapping = [RKEntityMapping mappingForEntityForName:kInviteTemplates
                                                             inManagedObjectStore:self.objectManager.managedObjectStore];
    invitationMapping = [RESTMappingProvider invitionTemplateMapping:invitationMapping];


    RKEntityMapping *activityMapping = [RKEntityMapping mappingForEntityForName:kActivityTemplates
                                                           inManagedObjectStore:self.objectManager.managedObjectStore];
    activityMapping =  [RESTMappingProvider activityTemplateMapping:activityMapping];

    [invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kTemplateActivitiesRelationship
                                                                                      toKeyPath:kTemplateActivitiesRelationship
                                                                                    withMapping:activityMapping]];

    STInvitesTemplate *invitation = [self templateForInvite];//this method assigns values to the attributes

    [self setupDescriptors:invitationMapping forKeyPath:kTemplatesKeyPath descriptorClassIsTemplate:YES];
    [self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];

    [self.objectManager postObject:invitation path:kTemplatesKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {

    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
    }];
}

Request & Response Descriptor:

- (void)setupDescriptors:(RKEntityMapping *)invitationMapping forKeyPath:(NSString *)keyPath descriptorClassIsTemplate:(BOOL)isTemplate
{

    RKRequestDescriptor *requestDescriptor;
    if (isTemplate)
    {
        requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[invitationMapping inverseMapping] objectClass:[Template class] rootKeyPath:nil method:RKRequestMethodAny];
    }
    else
    {
        requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[invitationMapping inverseMapping] objectClass:[Invite class] rootKeyPath:nil method:RKRequestMethodAny];
    }
    NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);

    RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:invitationMapping
                                                                                            method:RKRequestMethodGET
                                                                                       pathPattern:keyPath
                                                                                           keyPath:nil
                                                                                       statusCodes:statusCodeSet];

    self.objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
    [self.objectManager addRequestDescriptor:requestDescriptor];
    [self.objectManager addResponseDescriptor:responseDescriptor];

}

I know the approach above is incorrect as Xcode crashes after I POST or PUT. I haven't implemented Delete yet b/c I'm not sure how to set this up correctly.

Do I load the mappings ONCE in viewDidLoad? Do I create PUT, POST, DELETE x 2 EndPoints = 6 RKEntityMappings?

Need some guidance on best practice. Code sample or some step-by-step instructions would be great!

1条回答
太酷不给撩
2楼-- · 2019-09-10 07:12

You need to create an many different mappings as you have different structure responses to process. If the responses for one entity type are all subsets of some common superset then you can use just one (for mapping responses and another for requests). You don't say anything about the expected JSON so I can't tell.

In your code I see 2 request descriptors and 1 response descriptor. The requests match against any method so will always be used. The response descriptor matches only GET responses so won't work for anything. You should likely have one response descriptor per end point per method (as you say they need different mappings to be applied to each).

viewDidLoad isn't necessarily the correct place to configure this. It looks like you have a single object manager and this configuration code should run when it is created (not when it is used, brcause the view can be loaded multiple times and the configuration would be duplicated).

查看更多
登录 后发表回答