Parsing a simple JSON object with restkit - ios

I'm using restkit on IOS. I'm having trouble parsing a simple json object.
I have a simple json object returned:
{"_id"=>"537c235189d50fabcc000009",
"about"=>"nice",
"headline"=>"looking",
"access_token"=>
"$2a$10$oZ4IiaVBxHhc1qGeBoZv1uYonBM3Qb5Y010rTkUOynDZIGdGagqJy"}
My setup:
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRestKit];
[self loadVenues];
}
- (void)loadVenues
{
NSString *clientToken = SNAPTOKEN;
NSDictionary *profile = #{#"os": #"iOS",
#"device_token": #"first_token",
#"password":#"password",
#"email":#"email",
#"headline":#"hello world"};
NSDictionary *queryParams = #{#"token" : clientToken,
#"profile" : profile};
[[RKObjectManager sharedManager] postObject: nil
path: #"/profiles/new"
parameters:queryParams
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"log%#", mappingResult );
_profile = mappingResult.array;
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"What do you mean by 'there is no coffee?': %#", error);
}];
}
- (void)configureRestKit
{
// initialize AFNetworking HTTPClient
NSURL *baseURL = [NSURL URLWithString:#"https://airimg.com"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
// initialize RestKit
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
// setup object mappings
RKObjectMapping *venueMapping = [RKObjectMapping mappingForClass:[Profile class]];
[venueMapping addAttributeMappingsFromDictionary:#{ #"_id": #"about", #"access_token": #"headline" }];
// register mappings with the provider using a response descriptor
RKResponseDescriptor *responseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:venueMapping
method:RKRequestMethodPOST
pathPattern:#"/profiles/new"
keyPath:#"response"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:responseDescriptor];
}
I have the following error:
NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched: response
The representation inputted to the mapper was found to contain nested object representations at the following key paths: _id, about, access_token, headline
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}

The main problem is that your response descriptor uses a key path of response and your JSON doesn't include that key at the top level. So, set the key path to 'nil'.
Also, your view controller should store the reference to the objectManager and use it again later. Currently you use [RKObjectManager sharedManager] and that returns the first object manager that was ever created so as soon as you have multiple view controllers each creating their own object manager you will have issues.
Of course, the view controllers shouldn't necessarily be creating individual object managers...

Related

RestKit 0.24 || getObjectsAtPath || resulting object has NSString parameters set to NSNull

I am having NSString parameters in my object getting set to NSNull when null is returned in the JSON. I would like the the NSString to be set to nil. Any Ideas?
I have tried setting [mapping setAssignsDefaultValueForMissingAttributes:NO]; but that does not seem to work even when I implement changes from Fix 1714. I'm really just spinning my wheels at this point.
Here is everything I have for making this call so far.
Returned JSON
{
val1 = "something";
val2 = "<null>";
}
Class cMyClass
#interface cMyClass : NSObject {
NSString *val1;
NSString *val2;
}
RKObjectMapping
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[cMyClass class]];
[mapping addAttributeMappingsFromDictionary:#{#"val1":#"val1", #"val2":#"val2"}];
RKResponseDescriptor
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:#"GetMyClass" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectManager
NSURL *baseURL = [NSURL URLWithString:#"http://www.domain.com/MyAPI.svc/rest"];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
[objectManager addResponseDescriptor:responseDescriptor];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager.HTTPClient setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
[objectManager.HTTPClient setParameterEncoding:AFJSONParameterEncoding];
API Call
NSDictionary *params = ...
objectManager getObjectsAtPath:#"GetMyClass" parameters:params success:(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
completionBlock:(mappingResult.array[0]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
failureBlock(error);
}];
I'm grasping at straws since I am just starting out with Restkit myself...but, do you perhaps think there might be an issue with the mappings?
It looks like the values in your cMyClass are ivars instead of properties. If I am not mistaken, unless otherwise stated, those are "protected" so you can't really access those if you are calling an instance of the class. Maybe move them to properties and see if it works from there!

Restkit returning nil response from Foursquare API

I am trying to learn RestKit through "http://www.raywenderlich.com/58682/introduction-restkit-tutorial" and was simultaneously trying out the sample code provided on the site. Well my main problem is that the RestKit is not returning the response even though the request I send to API is correct and I get the response when I test it through browser.
Here is the code from the site (only change is I am sending in some other param):
- (void)configureRestKit
{
// initialize AFNetworking HTTPClient
NSURL *baseURL = [NSURL URLWithString:#"https://api.foursquare.com"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
// initialize RestKit
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
// setup object mappings
RKObjectMapping *venueMapping = [RKObjectMapping mappingForClass:[Venue class]];
[venueMapping addAttributeMappingsFromArray:#[#"name"]];
// register mappings with the provider using a response descriptor
RKResponseDescriptor *responseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:venueMapping
method:RKRequestMethodGET
pathPattern:#"/v2/venues/search"
keyPath:#"response.venues"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:responseDescriptor];
}
- (void)loadVenues
{
NSString *near = #"Chicago, IL";
NSString *clientID = kCLIENTID;
NSString *clientSecret = kCLIENTSECRET;
NSDictionary *queryParams = #{#"near" : near,
#"client_id" : clientID,
#"client_secret" : clientSecret,
#"categoryId" : #"4bf58dd8d48988d1e0931735",
#"v" : #"20140118"};
[[RKObjectManager sharedManager] getObjectsAtPath:#"/v2/venues/search"
parameters:queryParams
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
_venues = mappingResult.array;
[self.tableView reloadData];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"What do you mean by 'there is no coffee?': %#", error);
}];
}
Here is the API request URL:
https://api.foursquare.com/v2/venues/search?categoryId=4bf58dd8d48988d1e0931735&client_id=kCLIENTID&client_secret=kCLIENTSECRET&near=Chicago%2C%20IL&v=20150110
My 'mappingResult' object in the success block is coming out to be:
<RKMappingResult: 0x7cb4f6d0, results={
"response.venues" = (
);
}>
and 'operation' object is:
<RKObjectRequestOperation: 0x78e697c0, state: Successful, isCancelled=NO, request: <NSMutableURLRequest: 0x78e4f2f0> { URL: https://api.foursquare.com/v2/venues/search?categoryId=4bf58dd8d48988d1e0931735&client_id=kCLIENTID&client_secret=kCLIENTSECRET&near=Chicago%2C%20IL&v=20150110 }, response: <NSHTTPURLResponse: 0x79a46e40 statusCode=200 MIMEType=application/json length=35120>>
Any idea what is going on?
P.S. To test the URL I provided, you will need to replace kCLIENTID and kCLIENTSECRET with your client id and client secret info.
Change the queryParams to
NSString *ll = #"40.7,-74.20";
NSDictionary *queryParams = #{#"ll": ll,
#"client_id" : clientID,
#"client_secret" : clientSecret,
#"categoryId" : #"4bf58dd8d48988d1e0931735",
#"v": #"20140118"
};

RestKit - GETting a JSON array from a Rails app

I want to get this JSON data with my iOS app: https://sleepy-journey-2871.herokuapp.com/users.json .... RestKit tries to get these users from the url, but it returns 0 objects and says "No mappable representations were found at the key paths searched. No response descriptors match the response loaded."
PLEASE help me figure out what I'm missing or doing wrong! I've been battling this for weeks.
I have Xcode 5.0.2, I successfully installed RestKit with Cocoapods and a Podfile that looks like this:
platform :ios, '6.0'
pod 'RestKit', '~> 0.22.0'
pod 'RestKit/Testing'
pod 'RestKit/Search'
My AppDelegate.m file is below (the didFinishLaunchingWithOptions method):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
//Set base url
NSString *baseUrl = #"https://sleepy-journey-2871.herokuapp.com";
//initialize the the http client with baseUrl
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:baseUrl]];
//initialize the RKObjectManager with our http client
RKObjectManager *manager = [[RKObjectManager alloc] initWithHTTPClient:httpClient];
//add text/plain as a JSON content type to properly parse errors
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];
//register JSONRequestOperation to parse JSON in requests
[manager.HTTPClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
//state that we are accepting JSON content type
[manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
//configure so that we want the outgoing objects to be serialized into JSON
manager.requestSerializationMIMEType = RKMIMETypeJSON;
//set the shared instance of the object manager, so that we can easily re-use it later
[RKObjectManager setSharedManager:manager];
return YES;
}
I have this code in the viewDidLoad method of the view controller that first loads when the app is launched:
- (void)viewDidLoad
{
[super viewDidLoad];
RKObjectManager *manager = [RKObjectManager sharedManager];
[manager getObjectsAtPath:#"/users"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
NSLog(#"Loaded databases: %#", [mappingResult array]);
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", [error localizedDescription]);
}];
// Do any additional setup after loading the view, typically from a nib.
}
You have to:
Create a User class.
Create a mapping for User class.
Create a response descriptor.
Pseudocode could look something like:
#interface User : NSObject
#property (nonatomic, copy) NSNumber *userID;
#property (nonatomic, copy) NSString *name;
...
#end
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[User class]];
[mapping addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"id": #"userID"
...
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodAny
pathPattern:nil
keyPath:nil
statusCodes:nil];
...
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request
responseDescriptors:#[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSLog(#"The public timeline Tweets: %#", [result array]);
} failure:nil];
[operation start];
Take a look at examples here.

Restkit - Post object

I try to post an object Foobar (the class has two attributes: string foo and string bar) using the method postObject of the class RKObjectManager.
Server-side, I have a WCF service that receive the POST method
public void PostFoobar(Foobar foobar) { ... }
All the connection works. The problem is that the object foobar received is always NULL. It seems ResKit does not POST my object as an encapsulation of the two arguments, but post two string independently.
I mean, when I tryed to implement the following method (server-side) :
public void PostFoobar(string foo, string bar) { ... }
and the two parameters was not null ! it has worked !
But I would prefer to recover the serialized object obviously...
My question is :
How am I suppose to configure my POST request to recover an entire Foobar object on the server side, and not every attributes independently ?
My code
Here is my code to send the POST request
NSError *error = nil;
NSManagedObjectModel *managedObjectModel = #"myObjecModel";
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(persistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://192.168.1.10/rest"]];
objectManager.managedObjectStore = managedObjectStore;
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[RKObjectManager setSharedManager:objectManager];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:#"Foobar" inManagedObjectStore:managedObjectStore];
[postMapping addAttributeMappingsFromDictionary:#{
#"foo" : #"strFoo", // server side:foo, iOS side: strFoo
#"bar" : #"strBar" // server side:bar, iOS side: strBar
}];
RKRequestDescriptor * requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[postMapping inverseMapping] objectClass:[Foobar class] rootKeyPath:nil method:RKRequestMethodPOST];
[objectManager addRequestDescriptor:requestDescriptor];
// POST to create
RKManagedObjectStore *objectStore = [[RKObjectManager sharedManager] managedObjectStore];
Foobar *foobar = [NSEntityDescription insertNewObjectForEntityForName:#"Foobar" inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
foobar.strFoo = #"foo ipad";
foobar.strBar = #"bar ipad";
#try {
[[RKObjectManager sharedManager] postObject:foobar path:#"foobar" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", error.localizedDescription);
}];
}
#catch (NSException *exception) {
NSLog(#"error - %#", exception);
}
One more thing :
I have tested my web service with the chrome client "Simle REST client" and it works with the data :
{ "foo": "foo from chrome", "bar" : "bar from chrome" }
Edit - Frame capture with Wireshark
It seems to be good.. I don't understant.
You're calling with nil:
[[RKObjectManager sharedManager] postObject:nil path:#"foobar" parameters:nil ...
So RestKit is given nothing to serialise and no parameters.
If that's a typo, turn on trace logging for mapping and look at what it's doing. Also, get Charles or a similar tool and check exactly what data is being sent over the network.

Json Mapping using Restkit v0.20

i am able to send request correctly but after receiving response i get
response.body ={"status":"success","loginToken":"xxxxyyyzzz"}
but with an error saying
It Failed: Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No response descriptors
match the response loaded." UserInfo=0x2b55b0 {NSErrorFailingURLStringKey=http://192.168.1.71
/firstyii/index.php?r=site/login, NSLocalizedFailureReason=A 200 response was loaded from the
URL 'http://192.168.1.71/firstyii/index.php?r=site/login', which failed to match all (1)
response descriptors:
<RKResponseDescriptor: 0x2a5860 baseURL=http://192.168.1.71 pathPattern=/firstyii
/index.php?r=site/login statusCodes=200-299> failed to match: response path '/firstyii
/index.php?r=site/login' did not match the path pattern '/firstyii/index.php?r=site/login'.,
NSLocalizedDescription=No response descriptors match the response loaded., keyPath=null,
NSErrorFailingURLKey=http://192.168.1.71/firstyii/index.php?r=site/login,
NSUnderlyingError=0x2b6070 "No mappable object representations were found at the key paths
searched."}
LoginResponse.h
#interface LoginResponse : NSObject
#property (nonatomic, strong) NSString *status;
#property (nonatomic, strong) NSString *loginToken;
+(RKObjectMapping*)defineLoginResponseMapping;
#end
LoginResponse.m
#import "LoginResponse.h"
#implementation LoginResponse
#synthesize loginToken;
#synthesize status;
+(RKObjectMapping*)defineLoginResponseMapping {
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[LoginResponse class]];
[mapping addAttributeMappingsFromDictionary:#{
#"status": #"status",
#"loginToken": #"loginToken",
}];
return mapping;
}
#end
Code in LoginManager.m
-(void)LoginWithUserName:(NSString *)username password:(NSString*)password {
LoginRequest *dataObject = [[LoginRequest alloc] init];
[dataObject setUsername:username];
[dataObject setPassword:password];
NSURL *baseURL = [NSURL URLWithString:#"http://192.168.1.71"];
AFHTTPClient * client = [AFHTTPClient clientWithBaseURL:baseURL];
[client setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class]
forMIMEType:#"application/json"];
RKObjectMapping *requestMapping = [[LoginRequest defineLoginRequestMapping] inverseMapping];
[objectManager addRequestDescriptor: [RKRequestDescriptor
requestDescriptorWithMapping:requestMapping objectClass:[LoginRequest class] rootKeyPath:nil
]];
// what to print
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("Restkit/Network", RKLogLevelDebug);
RKObjectMapping *responseMapping = [LoginResponse defineLoginResponseMapping];
[objectManager addResponseDescriptor:[RKResponseDescriptor
responseDescriptorWithMapping:responseMapping pathPattern:#"/firstyii/index.php?r=site/login"
keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
[objectManager setRequestSerializationMIMEType: RKMIMETypeJSON];
[objectManager postObject:dataObject path:#"/firstyii/index.php?r=site/login"
parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"It Worked: %#", [mappingResult array]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"It Failed: %#", error);
}];
}
i think that the code used above is to map response with array ,
so i need code to map simple json like this one response.body={"status":"success","loginToken":"logingngngnnggngngae"}
Such responses are to be mapped using pathpattern , non keyvalue mapping mentioned at https://github.com/RestKit/RestKit/wiki/Object-mapping.
I was using pathPattern having "?" in it , hence it was not matching properly.
,also path pattern shouldnot have "/" at beginning.
the above code works fine if i change the pathPattern to pathPattern:#"site/login"
,and postObject to postObject:#"site/login"
and ofcourse changed the baseurl = #"http://json.xxxxxxx.xxxxx:8179/jsonresponse/index.php" so that there are not special charaters in it.

Resources