This question already has an answer here:
Restkit request not sending parameters
(1 answer)
Closed 8 years ago.
I have the following two entities
#interface MEContactInfo : NSObject
#property (nonatomic,strong) NSString* phone ;
#property (nonatomic,strong) NSString* email;
#end
#interface MEContact : NSObject
#property (nonatomic,strong) NSString* _id ;
#property (nonatomic,strong) NSString* lastName;
#property (nonatomic,strong) NSString* firstName;
#property (nonatomic,strong) NSString* data ;
#property (nonatomic,strong) NSMutableArray* contactInfos ;
#end
The second entity contact contains the array of contact infos. Now I want to post this to my server but I am not able to do so. My mappings are as following:
RKObjectMapping* contactMapping = [RKObjectMapping mappingForClass:[MEContact class]];
[contactMapping addAttributeMappingsFromArray:#[#"_id",#"lastName",#"firstName",#"data"]];
RKObjectMapping* contactInfosMapping = [RKObjectMapping mappingForClass:[MEContactInfo class]];
[contactInfosMapping addAttributeMappingsFromArray:#[#"email",#"phone"]];
[contactMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"contactInfos" toKeyPath:#"contactInfos" withMapping:contactInfosMapping]];
My request descriptor is as following:
requestDescriptor = [RKRequestDescriptor
requestDescriptorWithMapping:[contactMapping inverseMapping]
objectClass: [MEContact class]
rootKeyPath:nil method:RKRequestMethodAny];
Now when I post something like this:
{ firstName:”abc”,
lastName:”xyz”,
contactInfos: [{
email:”test#test.com”,
phone:”9999999999”
}]
}
I receive
{
firstName:”abc”,
lastName:”xyz”,
contactInfos: [ ”test#test.com”,”9999999999”]
}
If I have multiple entries in the contactInfos array, they all are appended to the contactInfos array I receive on the server side. Basically the contactInfo object is flattening in an array. Can you please let me know how I can fix this.
I got it to work. Everything above was correct. The problem was that data was not going as JSON to the server. The solution was that I had to set request serialization MimeType which can be done by doing this
[objectManger setRequestSerializationMIMEType:RKMIMETypeJSON];
Thanks
I've been trying to map the following object from the JSON response and from everything I see in the console output, there isn't any reason why the mapping isn't successful - I appreciate if anyone could have a check and see:
#interface RKElectionsModel : NSObject
#property (nonatomic, assign) bool isActive;
#property (nonatomic, strong) NSNumber *electionID;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *summary;
#property (nonatomic, strong) NSNumber *availableSeats;
#property (nonatomic, strong) NSNumber *candidatesCount;
#property (nonatomic, strong) NSNumber *withdrawnCount;
#property (nonatomic, strong) NSSet *candidates;
#end
/**
* Election Detail Mapping: Getting all election details, we have some extra information from
* the API call
*
*/
RKObjectMapping *electionDetailsMapping = [RKObjectMapping mappingForClass:[RKElectionsModel class]];
// Map JSON -> entities
[electionDetailsMapping addAttributeMappingsFromDictionary:#{
#"id": #"electionID",
#"title": #"title",
#"summary": #"summary",
#"active": #"isActive",
#"availableSeats": #"availableSeats",
#"candidatesCount": #"candidatesCount",
#"withdrawnCount": #"withdrawnCount"
}];
// Register our mappings with the provider
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:electionDetailsMapping pathPattern:#"/api/elections/:electionID/all" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
Console output on pastebin and any examples of the JSON response you can visit here
Appreciate any help,
Lewis
Seems like your trying to map a NSString to NSNumber.
In your NSObject try to add the following validation and transform the string you receive from the server to a NSNumber when the mapping starts.
- (BOOL)validateAvailableSeats:(id *)ioValue error:(NSError **)outError {
// Force the value to be a NSNumber
*ioValue = [NSNumber numberWithDouble:[(NSString*)value doubleValue] ]
return YES;
}
In the RestKit Wiki you'll find more transformations for your values.
I'm trying to load iTunes Search API results into custom objects using RestKit. I've defined a simple NSObject subclass for the results:
#interface LSiTunesResult : NSObject
#property (nonatomic) NSInteger itemID;
#property (nonatomic) NSInteger artistID;
#property (strong, nonatomic) NSString *title;
#property (strong, nonatomic) NSString *artistName;
#property (strong, nonatomic) NSString *collectionName;
#property (strong, nonatomic) NSString *itemDescription;
#property (strong, nonatomic) NSURL *imageURL;
#property (strong, nonatomic) NSURL *thumbnailURL;
#property (strong, nonatomic) NSURL *trackPreviewURL;
#property (strong, nonatomic) NSURL *trackViewURL;
//
+ (RKObjectMapping *)objectMapping;
#end
For simplicity's sake, I've defined object mapping
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[LSiTunesResult class]];
[mapping addAttributeMappingsFromDictionary:#{
#"artistName" : #"artistName"
}];
I've tried a few different ways to actually request the results, using both a custom RKObjectManager and an RKObjectRequestOperation. My simple example with RKObjectRequestOperation looks like:
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[LSiTunesResult objectMapping] pathPattern:nil keyPath:#"results" statusCodes:nil];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:urlRequest responseDescriptors:#[responseDescriptor]];
[operation.HTTPRequestOperation setAcceptableContentTypes:[NSSet setWithObject:#"text/javascript"]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"The search results are: %#", [mappingResult array]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure reason: %#", [error localizedDescription]);
}];
[operation start];
Unfortunately, I get the following error from RKResponseMapperOperation: "restkit.network:RKResponseMapperOperation.m:197 Failed to parse response data: Loaded an unprocessable response (200) with content type 'text/javascript'"
I have RestKit network logging on, and it appears that the response from the iTunes API marks the content type as 'text/javascript', while the body contains valid JSON. I've tried telling the RKObjectRequestOperation that text/javascript is an acceptable content type.
Does anyone have any experience with the iTunes API and RestKit? I'm curious if this is a simple mapping issue on my end, or if the iTunes API claiming the content type is javascript while it appears to be valid JSON is throwing off RestKit. Below is a sample of the iTunes Search API response that is logged during my example.
2012-10-21 01:48:54.061 Listen[99898:617] T restkit.network:RKHTTPRequestOperation.m:124 GET 'http://itunes.apple.com/search?term=The%20Lumineers&country=US&media=music&limit=1' (200):
response.headers={
"Cache-Control" = "no-transform, max-age=60";
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Length" = 519;
"Content-Type" = "text/javascript; charset=utf-8";
Date = "Sun, 21 Oct 2012 05:48:54 GMT";
Vary = "Accept-Encoding";
"X-Apple-Partner" = "origin.0";
"apple-timing-app" = "49 ms";
"x-apple-application-instance" = 1018018;
"x-apple-application-site" = NWK;
"x-apple-orig-url-path" = "/search?term=The%20Lumineers&country=US&media=music&limit=1";
"x-apple-translated-wo-url" = "/WebObjects/MZStoreServices.woa/ws/wsSearch?term=The%20Lumineers&country=US&media=music&limit=1";
"x-webobjects-loadaverage" = 0;
}
response.body=
{
"resultCount":1,
"results": [
{"wrapperType":"track", "kind":"music-video", "artistId":350720227, "trackId":516035614, "artistName":"The Lumineers", "trackName":"Ho Hey", "trackCensoredName":"Ho Hey", "artistViewUrl":"https://itunes.apple.com/us/artist/the-lumineers/id350720227?uo=4", "trackViewUrl":"https://itunes.apple.com/us/music-video/ho-hey/id516035614?uo=4", "previewUrl":"http://a404.v.phobos.apple.com/us/r30/Video/fd/81/e1/mzi.gxodlwda..640x256.h264lc.u.p.m4v", "artworkUrl30":"http://a1838.phobos.apple.com/us/r30/Video/v4/41/64/37/416437c2-c02e-4706-3f13-a47f50ec2ccc/Cover.40x30-75.jpg", "artworkUrl60":"http://a621.phobos.apple.com/us/r30/Video/v4/41/64/37/416437c2-c02e-4706-3f13-a47f50ec2ccc/Cover.80x60-75.jpg", "artworkUrl100":"http://a1629.phobos.apple.com/us/r30/Video/v4/41/64/37/416437c2-c02e-4706-3f13-a47f50ec2ccc/Cover.100x100-75.jpg", "collectionPrice":1.99, "trackPrice":1.99, "releaseDate":"2012-04-03T07:00:00Z", "collectionExplicitness":"notExplicit", "trackExplicitness":"notExplicit", "trackTimeMillis":160952.0, "country":"USA", "currency":"USD", "primaryGenreName":"Singer/Songwriter"}]
}
Two things to make this work.
The first one you got:
operation.HTTPRequestOperation.acceptableContentTypes = [NSSet setWithObject:#"text/javascript"];
The second one is to register the json serializer for this type.
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/javascript"];
Then it all works!
I have been using RestKit for sometime but some APIs have changed in the latest version and I'm no longer able to parse simple JSON.
Here's the payload I have:
{
"result":true,
"items":[
{
"id":"1",
"receiver":"11011101"
},
{
"id":"2",
"receiver":"11011101"
}
]
}
How can I parse the contents of the "items" dictionary as instances of the object Conversation I have created?
Using the code below doesn't work (objects are never mapped):
RKObjectMapping* conversationMapping = [RKObjectMapping mappingForClass:[Conversation class]];
[conversationMapping mapKeyPath:#"id" toAttribute:#"id"];
[conversationMapping mapKeyPath:#"receiver" toAttribute:#"receiver"];
[[RKObjectManager sharedManager].mappingProvider setMapping:conversationMapping forKeyPath:#"items"];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/getConversations" delegate:self];
Conversation class
#interface Conversation : NSObject {
NSString *id;
NSString *receiver; }
+ (void)objectMapping;
#property (nonatomic, strong) NSString *id; #property (nonatomic, strong) NSString *receiver;
#end
#implementation Conversation
#synthesize id;
#synthesize receiver;
+ (void)objectMapping {
RKObjectMapping* conversationMapping = [RKObjectMapping mappingForClass:[Conversation class]];
[conversationMapping mapKeyPath:#"id" toAttribute:#"id"];
[conversationMapping mapKeyPath:#"receiver" toAttribute:#"receiver"];
[[RKObjectManager sharedManager].mappingProvider setMapping:conversationMapping forKeyPath:#"items"];
}
#end
How is your root object defined (the one that holds "result" and your Conversation "items")? That should look something like this:
#interface MyResponse
#property (nonatomic, strong) NSArray* items;
#property (nonatomic, assign) BOOL result;
with the appropriate mapping for that as well.
I solved the problem. It was something totally not related to RestKit. The content type of the response coming back from the server was not set to JSON, after fixing that object mapping worked fine.
Hi all it's my first post in stack-overflow,
So First, thank you very much to everyone who shares!
My problems are :
I dont have callback return when I use RKObjectManager for POST Serialized object.
And I don't know if my use of Mapping data is correct ...
So I show you the result of my restful service (formated in JSON), my code and my restkit Logs
{"sessionId":"DA93D5ECD8E338AA27800794EEB9C20F","user":{"id":3,"ref":"2461498766","login":"clientTest","mail":"clientTest#Test.com","phone":"client127","subId":3,"creation":"29/03/2010 10:33:24","language":"en","firstConnection":"30/03/2010 16:42:07","lastConnection":"02/11/2011 09:36:43","connectionStep":"6"},"gateway":{"id":3,"serial":"testserial","status":"A","led":"START","ref":"DJJHGGGG00009","type":"FULL","ip":"192.168.44.168","connection":"","initDate":1290694795533,"activationDate":1290694795533,"manufacDate":1269851384000,"imei":"354482020013035","model":"TYLOP","firmware":"1.3.1","version":"","macWifi":"...","macEthernet":"...","updateDate":1310053274000,"muteMode":"","timezone":""}}
As you can see, we have a global Object with inside : User, Gateway Objects.
VOAuth.h, my global object used for data mapping :
#import "VOUser.h"
#import "VOGateway.h"
#interface VOAuth : NSObject
#property (nonatomic, retain) NSString * sessionId;
#property (nonatomic, retain) VOUser * user;
#property (nonatomic, retain) VOGateway * gateway;
#end
VOGateway.h,
#import <Foundation/Foundation.h>
#interface VOGateway : NSObject
#property (nonatomic, retain) NSString * identifier;
#property (nonatomic, retain) NSString * serial;
#property (nonatomic, retain) NSString * status;
#property (nonatomic, retain) NSString * led;
#property (nonatomic, retain) NSString * ref;
#property (nonatomic, retain) NSString * type;
#property (nonatomic, retain) NSString * ip;
#property (nonatomic, retain) NSString * connection;
#property (nonatomic, retain) NSString * initDate;
#property (nonatomic, retain) NSString * activationDate;
#property (nonatomic, retain) NSString * manufacDate;
#property (nonatomic, retain) NSString * imei;
#property (nonatomic, retain) NSString * model;
#property (nonatomic, retain) NSString * firmware;
#property (nonatomic, retain) NSString * version;
#property (nonatomic, retain) NSString * macWifi;
#property (nonatomic, retain) NSString * macEthernet;
#property (nonatomic, retain) NSString * updateDate;
#property (nonatomic, retain) NSString * muteMode;
#property (nonatomic, retain) NSString * timezone;
#end
VOUser.h,
#import <Foundation/Foundation.h>
#interface VOUser : NSObject
#property (nonatomic, retain) NSString * identifier;
#property (nonatomic, retain) NSString * ref;
#property (nonatomic, retain) NSString * login;
#property (nonatomic, retain) NSString * mail;
#property (nonatomic, retain) NSString * phone;
#property (nonatomic, retain) NSString * subId;
#property (nonatomic, retain) NSString * creation;
#property (nonatomic, retain) NSString * language;
#property (nonatomic, retain) NSString * firstConnection;
#property (nonatomic, retain) NSString * lastConnection;
#property (nonatomic, retain) NSString * connectionStep;
#end
SOAuth.h (my serialized object used as parameters for my call),
#import <Foundation/Foundation.h>
#interface SOAuth : NSObject
#property (nonatomic, retain) NSString* login;
#property (nonatomic, retain) NSString* password;
#end
MAModule.h (My manger, i call my restfull service here),
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#import "VOUser.h"
#import "VOGateway.h"
#import "VOAuth.h"
#import "SOAuth.h"
#interface MAModule : NSObject <RKObjectLoaderDelegate>
-(void)sendLogIn;
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects;
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error;
#end
MAModule.m,
#import "MAModule.h"
#implementation MAModule
-(void)sendLogIn
{
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:#"http://mydomain.dev/ui/v1"];
[RKObjectManager sharedManager].serializationMIMEType = RKMIMETypeJSON;
[manager.router routeClass:[SOAuth class] toResourcePath:#"/auth" forMethod:RKRequestMethodPOST];
RKObjectMapping* authSerializationMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class] ];
[authSerializationMapping mapAttributes:#"login", #"password", nil];
[[RKObjectManager sharedManager].mappingProvider setSerializationMapping:authSerializationMapping forClass:[SOAuth class] ];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[VOUser class]];
[userMapping mapKeyPath:#"id" toAttribute:#"identifier"];
[userMapping mapKeyPath:#"ref" toAttribute:#"ref"];
[userMapping mapKeyPath:#"login" toAttribute:#"login"];
[userMapping mapKeyPath:#"mail" toAttribute:#"mail"];
[userMapping mapKeyPath:#"phone" toAttribute:#"phone"];
[userMapping mapKeyPath:#"subId" toAttribute:#"subId"];
[userMapping mapKeyPath:#"creation" toAttribute:#"creation"];
[userMapping mapKeyPath:#"language" toAttribute:#"language"];
[userMapping mapKeyPath:#"firstConnection" toAttribute:#"firstConnection"];
[userMapping mapKeyPath:#"lastConnection" toAttribute:#"lastConnection"];
[userMapping mapKeyPath:#"connectionStep" toAttribute:#"connectionStep"];
RKObjectMapping *gatewayMapping = [RKObjectMapping mappingForClass:[VOGateway class]];
[gatewayMapping mapKeyPath:#"id" toAttribute:#"identifier"];
[gatewayMapping mapKeyPath:#"serial" toAttribute:#"serial"];
[gatewayMapping mapKeyPath:#"status" toAttribute:#"status"];
[gatewayMapping mapKeyPath:#"led" toAttribute:#"led"];
[gatewayMapping mapKeyPath:#"ref" toAttribute:#"ref"];
[gatewayMapping mapKeyPath:#"type" toAttribute:#"type"];
[gatewayMapping mapKeyPath:#"ip" toAttribute:#"ip"];
[gatewayMapping mapKeyPath:#"connection" toAttribute:#"connection"];
[gatewayMapping mapKeyPath:#"initDate" toAttribute:#"initDate"];
[gatewayMapping mapKeyPath:#"activationDate" toAttribute:#"activationDate"];
[gatewayMapping mapKeyPath:#"manufacDate" toAttribute:#"manufacDate"];
[gatewayMapping mapKeyPath:#"imei" toAttribute:#"imei"];
[gatewayMapping mapKeyPath:#"model" toAttribute:#"model"];
[gatewayMapping mapKeyPath:#"firmware" toAttribute:#"firmware"];
[gatewayMapping mapKeyPath:#"version" toAttribute:#"version"];
[gatewayMapping mapKeyPath:#"macWifi" toAttribute:#"macWifi"];
[gatewayMapping mapKeyPath:#"macEthernet" toAttribute:#"macEthernet"];
[gatewayMapping mapKeyPath:#"updateDate" toAttribute:#"updateDate"];
[gatewayMapping mapKeyPath:#"muteMode" toAttribute:#"muteMode"];
[gatewayMapping mapKeyPath:#"timezone" toAttribute:#"timezone"];
RKObjectMapping *authReturnMapping = [RKObjectMapping mappingForClass:[VOAuth class]];
[authReturnMapping mapKeyPath:#"sessionId" toAttribute:#"sessionId"];
[authReturnMapping mapKeyPath:#"user" toRelationship:#"user" withMapping:userMapping];
[authReturnMapping mapKeyPath:#"gateway" toRelationship:#"gateway" withMapping:gatewayMapping];
[[RKObjectManager sharedManager].mappingProvider setMapping:authReturnMapping forKeyPath:#""];
[[RKObjectManager sharedManager].mappingProvider setSerializationMapping:[authReturnMapping inverseMapping] forClass:[VOAuth class]];
NSLog(#"LOGIN SEND --------------------------------");
SOAuth *logObj = [[SOAuth alloc]init];
logObj.login = #"clientTest";
logObj.password = #"216a2e1269b5daaa35fd911964e5a86ce11f267d";
RKObjectMapping* authhMapping = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[VOAuth class] ];
[[RKObjectManager sharedManager] postObject:logObj mapResponseWith:authhMapping delegate:nil];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
//RKLogInfo(#"Load collection of Articles: %#", objects);
NSLog(#"LOGIN OK --------------------------------");
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
NSLog(#"LOGIN KO --------------------------------");
}
#end
I would like to highlight few points :
[[RKObjectManager sharedManager].mappingProvider setMapping:authReturnMapping forKeyPath:#""] : I have an empty key for my global object mapping, because I don't have root key for it ...
[[RKObjectManager sharedManager] postObject:logObj mapResponseWith:authhMapping delegate:nil]; My delegate is nil, else my application crash ...
LOGS :
2011-11-02 11:04:50.824 RestKit Installation[3701:207] D restkit.network:RKClient.m:265 Reachability observer changed for client <RKClient: 0x6d06e10>, suspending queue (null) until reachability to host '0.0.0.0' can be determined
2011-11-02 11:04:50.827 RestKit Installation[3701:207] LOGIN SEND --------------------------------
2011-11-02 11:04:50.833 RestKit Installation[3701:207] D restkit.network:RKClient.m:378 Reachability to host '0.0.0.0' determined for client <RKClient: 0x6d06e10>, unsuspending queue <RKRequestQueue: 0x6d09c10 name=(null) suspended=YES requestCount=1 loadingCount=0/5>
2011-11-02 11:04:50.836 RestKit Installation[3701:207] D restkit.network:RKRequest.m:334 Sending asynchronous POST request to URL http://mydomain.dev/ui/v1/auth.
2011-11-02 11:04:50.836 RestKit Installation[3701:207] D restkit.network:RKObjectLoader.m:302 POST or PUT request for source object <SOAuth: 0x9001540>, serializing to MIME Type application/json for transport...
2011-11-02 11:04:50.838 RestKit Installation[3701:207] T restkit.network:RKRequest.m:282 Prepared POST URLRequest '<NSMutableURLRequest http://mydomain.dev/ui/v1/auth>'. HTTP Headers: {
Accept = "application/json";
"Content-Length" = 75;
"Content-Type" = "application/json";
}. HTTP Body: {"login":"clientTest","password":"216a2e1269b5daaa35fd911964e5a86ce11f267d"}.
2011-11-02 11:04:51.432 RestKit Installation[3701:207] D restkit.network:RKResponse.m:196 NSHTTPURLResponse Status Code: 200
2011-11-02 11:04:51.433 RestKit Installation[3701:207] D restkit.network:RKResponse.m:197 Headers: {
Connection = close;
"Content-Length" = 763;
"Content-Type" = "application/json";
Date = "Wed, 02 Nov 2011 10:04:57 GMT";
}
2011-11-02 11:04:51.434 RestKit Installation[3701:207] T restkit.network:RKResponse.m:202 Read response body: {"sessionId":"DA93D5ECD8E338AA27800794EEB9C20F","user":{"id":3,"ref":"2461498766","login":"clientTest","mail":"clientTest#Test.com","phone":"client127","subId":3,"creation":"29/03/2010 10:33:24","language":"en","firstConnection":"30/03/2010 16:42:07","lastConnection":"02/11/2011 09:36:43","connectionStep":"6"},"gateway":{"id":3,"serial":"testserial","status":"A","led":"START","ref":"DJJHGGGG00009","type":"FULL","ip":"192.168.44.168","connection":"","initDate":1290694795533,"activationDate":1290694795533,"manufacDate":1269851384000,"imei":"354482020013035","model":"TYLOP","firmware":"1.3.1","version":"","macWifi":"...","macEthernet":"...","updateDate":1310053274000,"muteMode":"","timezone":""}}
2011-11-02 11:04:51.438 RestKit Installation[3701:6003] D restkit.network:RKObjectLoader.m:210 Found directly configured object mapping, creating temporary mapping provider for keyPath '%#'
Finally,
My callback functions are not called :
(void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
(void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error
Hoping someone can help me,
TY.
Your methods are not called, because you set nil as your delegate. As per our later discussion, if self is passed as the delegate, the subsequent crash is caused by MAModule being released too early. Use either property or singleton pattern to retain the MAModule object at least until your requests are completed.