I am working on Rest Kit 0.2o, I am using some sample URL for Json format from Web, the response is like Below. I am using Object Mapping. I am following the below link as reference
"https://github.com/RestKit/RestKit/wiki/Object-Mapping" I am using almost same response given in the link.
{
"geonames": [
{
"fcodeName":"capital of a political entity",
"toponymName":"Mexico City",
"countrycode":"MX",
"fcl":"P",
"fclName":"city, village,...",
"name":"Mexiko-Stadt",
"wikipedia":"en.wikipedia.org/wiki/Mexico_City",
"lng":-99.12766456604,
"fcode":"PPLC",
"geonameId":3530597,
"lat":19.428472427036,
"population":12294193
},
{
"fcodeName":"capital of a political entity",
"toponymName":"Manila",
"countrycode":"PH",
"fcl":"P",
"fclName":"city,village,...",
"name":"Manila",
"wikipedia":"en.wikipedia.org/wiki/Manila",
"lng":120.9822,
"fcode":"PPLC",
"geonameId":1701668,
"lat":14.6042,
"population":10444527
}]
}
Below is the code
RKObjectMapping *newsMapping = [RKObjectMapping mappingForClass:[News class]];
[newsMapping addAttributeMappingsFromDictionary:#{
#"fcodeName": #"fcodeName",
#"toponymName": #"toponymName",
#"countrycode": #"countrycode",
#"fcl": #"fcl",
#"fclName": #"fclName",
#"name":#"name",
#"wikipedia":#"wikipedia",
#"lng":#"lng",
#"fcode":#"fcode",
#"geonameId":#"geonameId",
#"lat":#"lat",
#"population":#"population",
}];
RKResponseDescriptor* responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:newsMapping
pathPattern:nil
keyPath:#"newsMapping"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
NSURL* url = [[NSURL alloc]initWithString:#"http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[ responseDescriptor ]];
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(#"Load collection of Articles: %#", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
// RKLogError(#"Operation failed with error: %#", error);
NSLog(#"THIS IS TEST %#",error);
}];
[objectRequestOperation start];
"News" is the class i am using and KeyPath i am using is "geonames"
#interface News : NSObject
#property(nonatomic,copy)NSString* fcodeName;
#property(nonatomic,copy)NSString* toponymName;
#property(nonatomic,copy)NSString* countrycode;
#property(nonatomic,copy)NSString* fcl;
#property(nonatomic,copy)NSString* fclName;
#property(nonatomic,copy)NSString* name;
#property(nonatomic,copy)NSString* wikipedia;
#property(nonatomic,copy)NSString* lng;
#property(nonatomic,copy)NSString* fcode;
#property(nonatomic,copy)NSString* geonameId;
#property(nonatomic,copy)NSString* lat;
#property(nonatomic,copy)NSString* population;
After doing all this I am getting below error
2013-05-30 12:06:14.376 TestApp[7140:11603] I restkit.network:RKObjectRequestOperation.m:174 GET 'http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo'
2013-05-30 12:06:15.477 TestApp[7140:12b07] E restkit.network:RKObjectRequestOperation.m:236 Test GET 'http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo' (200 OK / 0 objects) [request=1.0969s mapping=0.0000s total=1.1056s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable object representations were found at the key paths searched." UserInfo=0x7675f20 {DetailedErrors=(
), NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched: newsMapping
The representation inputted to the mapper was found to contain nested object representations at the following key paths: status
This likely indicates that you have misconfigured the key paths for your mappings., NSLocalizedDescription=No mappable object representations were found at the key paths searched., keyPath=null}
2013-05-30 12:06:15.477 TestApp[7140:14d03] blockk
2013-05-30 12:06:15.478 TestApp[7140:14d03] erorrrrrr next ifr
2013-05-30 12:06:15.478 TestApp[7140:14d03] erorrrrrr next ifjhkr
2013-05-30 12:06:15.478 TestApp[7140:11603] THIS IS TEST Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable object representations were found at the key paths searched." UserInfo=0x7675f20 {DetailedErrors=(
), NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched: newsMapping
The representation inputted to the mapper was found to contain nested object representations at the following key paths: status
This likely indicates that you have misconfigured the key paths for your mappings., NSLocalizedDescription=No mappable object representations were found at the key paths searched., keyPath=null}
Actually in error it is showing keyPath as null in last line But in Browser i am getting the response i have mentioned above.
Please Help
Your response descriptor keypath is wrong. Change to:
RKResponseDescriptor* responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:newsMapping pathPattern:nil keyPath:#"geonames" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
The error you're seeing currently would seem to be because the JSON actually returned is:
{"status":{"message":"the deaily limit of 30000 credits for demo has been exceeded. Please use an application specific account. Do not use the demo account for your application.","value":18}}
Which obviously does not match what you're expecting...
Related
When a user signs up successfully on our server, it responds with a 200 status code and a JSON payload like this:
{
"error": null,
"result": {
"auth": {
"created_utc": 1420740197,
"device_token": "rQZJddrbD5tyEpznb8bVKeGlHqRNGyvOgDR;tQJBkpkfAXO6DQ4lNiG17lzu6IDc0hVBfR3RrN9o0txRQIYAa6fnf5d9LNaSRDMk9LrplgkITuMC37v;;;rvG35CJvV7dWZ5TQVYUWeHwAABvKvzTRpSDw5Qg9jQrmiUHLZptegFY=76421420740197"
},
"display_name": "a",
"email": "a#a.com",
"user_id": 7642,
"username": "a"
}
}
But if a#a.com tries to sign up again, it responds with a 400 status code and a JSON payload like this:
{
"error": {
"code": 805,
"message": "there is another user with that username"
},
"result": null
}
I tried mapping the error, so that when Restkit returns an error, I get the message as well as the code. These are the ways I tried to do that:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:#"error.message" toKeyPath:#"errorMessage"]];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[self.objectManager addResponseDescriptor:errorDescriptor];
This one obviously only gets the message part of the error to return with this output:
Error Domain=org.restkit.RestKit.ErrorDomain Code=1004 "there is another user with that username" UserInfo=0x7feefcf8a730 {RKObjectMapperErrorObjectsKey=(
"there is another user with that username"
), NSLocalizedDescription=there is another user with that username}
So then I tried making a subclass of RKErrorMessage:
#import "RKErrorMessage.h"
#interface TAG_RKErrorMessage : RKErrorMessage
#property (strong, nonatomic) NSNumber *errorCode;
#end
And changed the mapping to this:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[TAG_RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:#"error.message" toKeyPath:#"errorMessage"]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:#"error.code" toKeyPath:#"errorCode"]];
and that resulted in the exact same output:
Error Domain=org.restkit.RestKit.ErrorDomain Code=1004 "there is another user with that username" UserInfo=0x7fa16c627ce0 {RKObjectMapperErrorObjectsKey=(
"there is another user with that username"
), NSLocalizedDescription=there is another user with that username}
So lastly I tried this mapping to at least try to get the dictionary show up as the RKObjectMapperErrorObjectsKey of the NSError's userInfo:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:#"error" toKeyPath:#"errorMessage"]];
And that resulted in this output:
Error Domain=org.restkit.RestKit.ErrorDomain Code=1004 "<null>" UserInfo=0x7ff8abe678e0 {RKObjectMapperErrorObjectsKey=(
(null)
), NSLocalizedDescription=<null>}
Now I'm stuck at this point. How can I map the keys of my server's error response so that I can get access to the code that is returned as well as the message as two separate values?
You've likely mapped your TAG_RKErrorMessage instance correctly. Have you attempted to extract it from the NSError you've been given? You can use the RKObjectMapperErrorObjectsKey as a key on the NSError's userInfo dictionary to get an array of all mapped error messages:
NSArray* objectMapperErrorObjectsArray = [error.userInfo objectForKey:RKObjectMapperErrorObjectsKey];
You can then loop through that array to check each error for conditions you want to respond to, for example, if you wanted to respond to a 403 response code with the error message "Invalid token", you could do:
NSArray* objectMapperErrorObjectsArray = [error.userInfo objectForKey:RKObjectMapperErrorObjectsKey];
for (RKErrorMessage* objectMapperErrorObject in objectMapperErrorObjectsArray)
{
if ([objectMapperErrorObject.errorMessage isEqual:#"Invalid token"])
{
if (operation.HTTPRequestOperation.response.statusCode == 403)
{
//Code to handle a 403 response status code when error message is "Invalid token".
}
}
}
Just a hint: if you want to use the built-in RKErrorMessage without creating any subclass, you can map all error JSON attributes to RKErrorMessage.userInfo in this way:
Objective-C:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:#"userInfo"]];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:"error" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
Swift:
let errorMapping = RKObjectMapping(forClass: RKErrorMessage.self);
errorMapping.addPropertyMapping(RKAttributeMapping(fromKeyPath: nil, toKeyPath: "userInfo"));
let errorResponseDescriptor = RKResponseDescriptor(
mapping: errorMapping,
method: RKRequestMethod.Any,
pathPattern: nil,
keyPath: "error",
statusCodes: RKStatusCodeIndexSetForClass(UInt(RKStatusCodeClassClientError)))
);
Im making an app that communicates with a rails based backend server.
I already have all the server calls ready and working via RESTKit, but I am having
problems with creating error mappings for my update calls.
My response descriptors for one of my classes
RKResponseDescriptor *descriptor = [RKResponseDescriptor responseDescriptorWithMapping:[Mappings liveViewMapping]
method:RKRequestMethodAny
pathPattern:nil
keyPath:#"event_enriched"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self addResponseDescriptor:descriptor];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[Mappings errorMapping]
method:RKRequestMethodAny
pathPattern:nil
keyPath:#"error"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[self addResponseDescriptor:errorDescriptor];
Edit: I've also tried it with keyPath "errors" and 'nil' .. same results
My error mapping is quite simple:
+ (RKObjectMapping *)errorCollectionMapping {
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[ErrorCollection class]];
NSDictionary *mappingDictionary = #{#"error" : #"message",
#"errors" : #"messages",
};
[errorMapping addAttributeMappingsFromDictionary:mappingDictionary];
return errorMapping;
}
This is how I am trying to update my Book object
[self putObject:book
path:API_BOOK
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
if (success) {
Book *book = [mappingResult.dictionary objectForKey:#"book"];
success(book);
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
if (failure) failure(operation, error);
}
];
But when I get a server error, which should be handled by my response descriptor I get the following error:
Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable object representations were found at the key paths searched." UserInfo=0x7f935d07c7a0 {NSLocalizedDescription=No mappable object representations were found at the key paths searched., NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched: book
The representation inputted to the mapper was found to contain nested object representations at the following key paths: error, error_description
This likely indicates that you have misconfigured the key paths for your mappings., keyPath=null, DetailedErrors=(
)}
What am I doing wrong?
I already have some GET requests, that have multiple mappings (non of them is an error mapping yet) which works fine, but can't "replicate" the same behavior with error mapping
oh.. I am using restkit-0.24 :)
edit:
the error responses coming back from my rails server are in this form:
{"errors": ["error1", "error2" ... ] }
or
{"error": "error message" }
i feel so stupid right now ...
The server responses had code 200 and not the 400-499 range that RKStatusCodeClassClientError predicts.
OK, so I've reviewed almost every single one of the other questions on this site, to no avail.
Here's my JSON that comes back from a REST service:
{
"errors" : {};
"result" : {
"messagebody" : "Hello!";
"timestamp" : "2014-08-21T04:12:28.4689099+00:00";
};
"success" : {};
}
I am trying to pull out the result object via RestKit v0.20.3
Here's a block of my code where it gets configured/executed:
- (void) configureRestKit
{
NSURL *cminstance = [NSURL URLWithString:#"http://<domain>"];
AFHTTPClient *cmclient = [[AFHTTPClient alloc] initWithBaseURL:cminstance];
RKObjectManager *objmgr = [[RKObjectManager alloc] initWithHTTPClient:cmclient];
RKObjectMapping *messageMap = [RKObjectMapping mappingForClass:[Message class]];
[messageMap addAttributeMappingsFromDictionary:#{ #"messagebody" : #"messagebody", #"timestamp": #"timestamp"}];
messageMap.forceCollectionMapping = YES;
RKResponseDescriptor *descriptor =
[RKResponseDescriptor
responseDescriptorWithMapping:messageMap
method:RKRequestMethodGET
pathPattern:#"/v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test"
keyPath:#"result"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objmgr addResponseDescriptor:descriptor];
}
- (IBAction)helloButtonClicked:(id)sender {
[[RKObjectManager sharedManager].HTTPClient setDefaultHeader:#"X-App-ApiKey" value:#"2c130c75dc9f4c2c8ef7c8753e8b7c56"];
NSLog(#"ResponseDescriptors %#", [[RKObjectManager sharedManager] responseDescriptors]);
[[RKObjectManager sharedManager] getObjectsAtPath:#"/v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
_Response.text = [mappingResult.dictionary objectForKey:#"messagebody"];
} failure:^(RKObjectRequestOperation *operation, NSError *error)
{
_Response.text = #"Something went wrong.";
}];
}
Here's the error from the trace:
2014-08-21 00:12:30.653 The-App[13924:3707] E restkit.network:RKObjectRequestOperation.m:208 GET 'http:///v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test' (200 OK / 0 objects) [request=2.7297s mapping=0.0000s total=2.7365s]:
error=Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No response descriptors match the response loaded." UserInfo=0xb164380 {NSErrorFailingURLStringKey=http:///v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test, NSLocalizedFailureReason=A 200 response was loaded from the URL 'http:///v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test', which failed to match all (0) response descriptors:, NSLocalizedDescription=No response descriptors match the response loaded., keyPath=null, NSErrorFailingURLKey=http:///v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test, NSUnderlyingError=0xb1641c0 "No mappable object representations were found at the key paths searched."}
response.body={"success":{},"errors":{},"result":{"messagebody":"Hello!","timestamp":"2014-08-21T04:12:28.4689099+00:00"}}
Any ideas here on how to troubleshoot? I've been banging my head on this one for a few hours and google has not been my friend.
EDIT: The Response Descriptors
2014-08-22 10:41:21.580 Apprenda-CloudMine-App[10987:60b] ResponseDescriptors (
"<RKResponseDescriptor: 0x17826c180 method=(GET) pathPattern=/v1/app/e51cb2dd24af47a49232b942210e758d/text?f=test keyPath=result statusCodes=200-299 : <RKObjectMapping:0x17826bfc0 objectClass=Message propertyMappings=(\n \"<RKAttributeMapping: 0x1780499f0 timestamp => timestamp>\",\n \"<RKAttributeMapping: 0x17804cf30 messagebody => messagebody>\"\n)>>"
)
Thanks!
-Chris
That error indicates that the path between your request and your response descriptor are not matching. It is subtle, the (0) response descriptors in the error message also indicate to me that there are no response descriptors for that path. For more information on the error messages for RestKit path mismatches see this GitHub issue.
Why then are you getting a path mismatch? After all, the path in your request is exactly the same as your path in your response descriptor. It would seem that your problem is likely the GET parameter specified in the response descriptors path. You need to remove the get parameter from your response descriptors path since it is not technically part of the path.
It should be the following instead.
[RKResponseDescriptor
responseDescriptorWithMapping:messageMap
method:RKRequestMethodGET
pathPattern:#"/v1/app/e51cb2dd24af47a49232b942210e758d/text"
keyPath:#"result"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
Thanks to Flaviu Simihaian for realizing this.
I receive this error when I attempt to use postObject in XCODE 5 for iOS 7:
Here is the error message without the URLs which point to https:// service
E restkit.network:RKObjectRequestOperation.m:542 Object request failed: Underlying HTTP request operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html" UserInfo=0xb9a44f0 {NSLocalizedRecoverySuggestion={"status": "ok"}, AFNetworkingOperationFailingURLRequestErrorKey=<NSMutableURLRequest: 0x8dd14c0> { URL: http:
NSLocalizedDescription=Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0xb998d30>
{ status code: 200, headers {
Connection = close;
"Content-Length" = 16;
"Content-Type" = "text/html; charset=utf-8";
Any object the I put in postObject method just returns text/html and not JSON. I does not appear to use the requestDescriptor or requestMapping that I defined. Its simply posting the object as text/html.
Is there another method of posting using RestKit?
Is there a fix or workaround for this issue?
Here's my code sample:
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping]; // objectClass == NSMutableDictionary
[requestMapping addAttributeMappingsFromArray:#[#"email", #"nickname"]];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[RegisterDeviceInfo class] rootKeyPath:nil method:RKRequestMethodAny];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:_uuidURL]];
[RKObjectManager setSharedManager:objectManager];
[objectManager addRequestDescriptor:requestDescriptor];
RegisterDeviceInfo *deviceInfo = [RegisterDeviceInfo new];
deviceInfo.email = email;
deviceInfo.nickname = nickname;
// This is not accepted by the postObject and mapped to JSON object using above mappings and requestDescriptor
NSLog(#"deviceInfo is: %#", deviceInfo);
[[RKObjectManager sharedManager] postObject:deviceInfo path:(_uuidURL) parameters:nil success: nil failure: nil];
NSLog(#"deviceInfo is: %#", deviceInfo);
You should show the rest of the error (the lines before what you show). This is about the response, not the request. An HTML response often means an error message and you need to see what that is to know what's wrong.
The issue appears to be that you are using (_uuidURL) as the path when you call postObject but that it is the full URL.
The path should be relative to the base URL that was used to create the object manager. i.e.
baseURL = #"www.myserver.com/"
path = #"mycontent"
I'm extremely stuck on mapping a simple JSON object:
{"articles":
[{"id":"354633","lat":"51.501","lng":"-0.125","type":"railwaystation","title":"Westminster tube station","url":"http:\/\/en.wikipedia.org\/w\/index.php?curid=354633","distance":"53m"},
{"id":"92601","lat":"51.5011","lng":"-0.125","type":"railwaystation","title":"17 - Westminster tube station","url":"http:\/\/en.wikipedia.org\/w\/index.php? curid=92601","distance":"62m"},
{"id":"92598","lat":"51.5011","lng":"-0.125","type":"railwaystation","title":"34 -Westminster tube station","url":"http:\/\/en.wikipedia.org\/w\/index.php?curid=92598","distance":"62m"}]
}
I'm really puzzled by the problem I'm having, since this is almost identical to the JSON in the RestKit Mapping Guide.
My code is:
self.articleMapper = [RKObjectMapping mappingForClass:[WikiArticle class]];
[self.articleMapper mapKeyPath:#"title" toAttribute:#"title"];
[[RKObjectManager sharedManager].mappingProvider setMapping:self.articleMapper forKeyPath:#"articles"];
I'm getting the following error in the log:
restkit.object_mapping:RKObjectMappingOperation.m:339 Did not find mappable attribute value keyPath 'title'
restkit.object_mapping:RKObjectMappingOperation.m:557 Mapping operation did not find any mappable content
restkit.object_mapping:RKObjectMapper.m:308 The following operations are in the queue: ()
restkit.object_mapping:RKObjectMapper.m:323 Finished performing object mapping. Results: {}
Thanks in advance for helping me out with something so simple -- I've been banging my head against it for hours!
-Alex
I suppose you call it in a way like this:
[objectManager loadObjectsAtResourcePath:url delegate:self block:^(RKObjectLoader* loader) {
loader.objectMapping = [objectManager.mappingProvider objectMappingForClass:[WikiArticle class]];
}];
Better try:
[objectManager loadObjectsAtResourcePath:url delegate:self];