RestKit — отправка POST и получение ответа сопоставлены

Итак, я использую RestKit версии 0.20 и успешно отправляю запрос POST в формате JSON. Бэкэнд моего сервера (Java REST WS (Джерси)) отображает все правильно, как и Restkit.

Моя проблема в том, что я отправляю другой объект обратно, поскольку у меня есть сообщение. У меня есть следующая настройка сопоставления в RestKit:

- (void)createUserAccount:(DeviceDTO *)devDTO :(UserDTO *)userDTO block:(void (^)(id))block{
    id errorCode __block;
    // Configure a request mapping for our Article class. We want to send back title, body, and publicationDate
    RKObjectMapping* deviceRequestMapping = [RKObjectMapping requestMapping];
    [deviceRequestMapping addAttributeMappingsFromArray:@[ @"model", @"name", @"systemName", @"systemVersion", @"devToken" ]];

    RKObjectMapping* msRequestMapping = [RKObjectMapping requestMapping];
    [msRequestMapping addAttributeMappingsFromArray:@[ @"validSince", @"validTill" ]];

    RKObjectMapping* countryRequestMapping = [RKObjectMapping requestMapping];
    [countryRequestMapping addAttributeMappingsFromArray:@[ @"idNumberDTO", @"iso2DTO", @"short_nameDTO", @"calling_codeDTO" ]];

    RKObjectMapping* contactsRequestMapping = [RKObjectMapping requestMapping];
    [contactsRequestMapping addAttributeMappingsFromArray:@[ @"fullName", @"phoneNumber"]];

    RKObjectMapping* userRequestMapping = [RKObjectMapping requestMapping];
    [userRequestMapping addAttributeMappingsFromArray:@[ @"displayName", @"phoneNumber", @"status", @"userID", @"realName" ]];

    [userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"deviceInfo" toKeyPath:@"device" withMapping:deviceRequestMapping]];
    [userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"memberShipDetails" toKeyPath:@"memberShip" withMapping:msRequestMapping]];
    [userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"country" toKeyPath:@"country" withMapping:countryRequestMapping]];
    [userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"contacts" toKeyPath:@"contacts" withMapping:contactsRequestMapping]];

    RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userRequestMapping objectClass:[UserDTO class] rootKeyPath:nil];


    //Create Objects
    UserDTO *user = [[UserDTO alloc]init];
    ..........

    DeviceDTO *device = [[DeviceDTO alloc]init];
    ..........

    user.deviceInfo = device;

    MemberShipDTO *ms = [[MemberShipDTO alloc]init];
    .......

    user.memberShipDetails = ms;



    RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[ErrorMapping class]];
    [errorMapping addAttributeMappingsFromArray:@[ @"errorCode", @"errorMessage" ]];

    RKObjectMapping* deviceRespMapping = [RKObjectMapping mappingForClass:[DeviceDTO class]];
    [deviceRespMapping addAttributeMappingsFromArray:@[ @"model", @"name", @"systemName", @"systemVersion", @"devToken" ]];

    RKObjectMapping* msRespMapping = [RKObjectMapping mappingForClass:[MemberShipDTO class]];
    [msRespMapping addAttributeMappingsFromArray:@[ @"validSince", @"validTill" ]];

    RKObjectMapping* contactsRespMapping = [RKObjectMapping mappingForClass:[ContactDTO class]];
    [contactsRespMapping addAttributeMappingsFromArray:@[ @"fullName", @"phoneNumber"]];

    RKObjectMapping* userRespMapping = [RKObjectMapping mappingForClass:[UserDTO class]];
    [userRespMapping addAttributeMappingsFromArray:@[ @"displayName", @"phoneNumber", @"status", @"userID", @"realName" ]];

    [userRespMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"deviceInfo" toKeyPath:@"device" withMapping:deviceRespMapping]];
    [userRespMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"memberShipDetails" toKeyPath:@"memberShip" withMapping:msRespMapping]];
    [userRespMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"country" toKeyPath:@"country" withMapping:countryRequestMapping]];
    [userRespMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"contacts" toKeyPath:@"contacts" withMapping:contactsRespMapping]];

    [errorMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"user" toKeyPath:@"user" withMapping:userRespMapping]];

    RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"application/json"];

    [[RKObjectManager sharedManager] setRequestSerializationMIMEType:RKMIMETypeJSON];
    [[RKObjectManager sharedManager] setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
    [[RKObjectManager sharedManager] addRequestDescriptor:requestDescriptor];
    [[RKObjectManager sharedManager] addResponseDescriptor:errorDescriptor];
    [[RKObjectManager sharedManager] postObject:user path:@"user/integrate" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
        NSArray* statuses = [mappingResult array];
        NSLog(@"Loaded statuses: %@", statuses);
        errorCode = [statuses objectAtIndex:0];
        NSLog(@"errorCode == %@", errorCode);
        block(errorCode);
        RKLogInfo(@"Load collection of Articles: %@", mappingResult.array);
    }failure:^(RKObjectRequestOperation *operation, NSError *error) {
        block(nil);
        RKLogError(@"Operation failed with error: %@", error);
    }];

}

Мой JSON по моему запросу в порядке, и ответ тоже в порядке:

{
    "errorMessage": null,
    "errorCode": 190,
    "user": {
        "displayName": "Saif",
        "phoneNumber": "+xxx",
        "userID": "xxx",
        "country": {
            "idNumberDTO": 83,
            "short_nameDTO": "Germany",
            "calling_codeDTO": "+49",
            "iso2DTO": "DE"
        },
        "device": {
            "devToken": "xxx",
            "model": "iPhone",
            "name": "Saifs iPhone",
            "systemName": "iPhone OS",
            "systemVersion": "6.1.4",
            "id": null
        },
        "memberShip": {
            "validSince": 1376047810000,
            "validTill": 1407583810000,
            "id": null
        },
        "contacts": [
            {
                "fullName": "xxx",
                "phoneNumber": "xxx"
            },
            {
                "fullName": "xxx",
                "phoneNumber": "xxx"
            },
            ....,
            ....,
            ....
        ],
        "id": null
    }
}

В моем методе RK я получаю эту строку:

    errorCode = [statuses objectAtIndex:0];

эта ошибка:

2013-08-09 13:30:12.246 xxx![19310:440f] W restkit.object_mapping:RKMapperOperation.m:99 Adding mapping error: Expected an object mapping for class of type 'UserDTO', provider returned one for 'ErrorMapping'
2013-08-09 13:30:12.247 xxx![19310:440f] I restkit.network:RKObjectRequestOperation.m:250 POST 'http://192.168.2.115:8080/WAZZUUPWS/rest/service/user/integrate' (200 OK / 0 objects) [request=1.3406s mapping=0.0047s total=1.3461s]
2013-08-09 13:30:12.249 xxx![19310:907] Loaded statuses: (
)
2013-08-09 13:30:12.250 xxx![19310:907] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'

Похоже, что ответ не может быть сопоставлен, поэтому массив результатов пуст. Любая идея, как я могу отобразить сложный объект из ответа?


person SaifDeen    schedule 09.08.2013    source источник


Ответы (1)


Из документации по Restkit:

По умолчанию при использовании postObject или putObject RestKit автоматически попытается сопоставить результат JSON с опубликованным исходным объектом.

В своем коде вы публикуете экземпляр UserDTO и получаете ответ JSON, который должен сопоставляться с ErrorMapping. Следовательно, вы получаете RKMappingErrorTypeMismatch из Restkit.

Как объясняется в документации, вместо использования post вы можете сами создать RKRequestOperation и обнулить целевой объект, чтобы переопределить значения по умолчанию.

RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] appropriateObjectRequestOperationWithObject:user
                                                                                                            method:RKRequestMethodPOST
                                                                                                              path:@"user/integrate"
                                                                                                        parameters:nil];
operation.targetObject = nil;

[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    DLog(@"integrated user: %@", mappingResult.firstObject);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    DLog(@"error integrating user: %@", user);
}];

Однако, если вы можете изменить серверную часть, я бы предпочел изменить возвращаемый JSON. Вместо того чтобы включать коды ошибок в ответ JSON, используйте соответствующие коды состояния ответа (HTTP) и включайте в свои ответы только объекты, относящиеся к модели предметной области.

person serrrgi    schedule 09.08.2013
comment
Ммм. Не могли бы вы попытаться привести пример для RKRequestOperation?? - person SaifDeen; 09.08.2013
comment
-.- все время пытался вот так [[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation]; - person SaifDeen; 10.08.2013
comment
Сорри, я немного поторопился. Я копирую ваш пример кода, но операция не была опубликована. Я обновил ваш код, чтобы завершить ваш ответ. - person SaifDeen; 10.08.2013
comment
[начало операции]; скучал - person SaifDeen; 10.08.2013