I am searching a way to map 2 different arrays with the following JSON
"establishments": [
{
"id": 1,
"name": "Boudin Sourdough Bakery and Cafe",
"address": "1 Stockton St",
"zip_code": "94108",
"city": "San Francisco",
"country": "us",
"phone_number": "",
"position": {
"latitude": 37.78590500000001,
"longitude": -122.406289
},
"distance_from": 13.75783097391759
}
],
"places": [
{
"id": 3,
"name": "Private Place",
"position": {
"latitude": 37.78583400000001,
"longitude": -122.406417
},
"is_private": false,
"distance_from": 0
}
]
I have 2 different mappings. One for establishment and another for place. I found some help with the documentation but it's working only for PUT or POST requests.
Currently, I have the following request
[session.objectManager getObjectsAtPathForRouteNamed:APICallSearchSearchPlaceRouteName object:nil parameters:params success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray * resultPlaces=mappingResult.array;
[delegate APICallDidSearch:resultPlaces];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSError* myError=[self catchCustomErrorInRKError:error setDomain:#"Search"];
if (myError.code == NSURLErrorCancelled) return;
[delegate APICallDidFailSearch:myError];
}];
Mapping & Mapping Descriptor
RKEntityMapping *establishmentMapping = [APICallEstablishment RKGetEstablishmentMappingForManagedObjectStore:self.appDelegate.managedObjectStore];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:establishmentMapping
method:RKRequestMethodGET
pathPattern:APICallSearchSearchPlacePattern
keyPath:#"establishments"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[session.objectManager addResponseDescriptor:responseDescriptor];
I tried to adapt the example to my case with that (just before my request written above)
RKManagedObjectRequestOperation *operation = [session.objectManager appropriateObjectRequestOperationWithObject:establishmentMapping method:RKRequestMethodGET path:#"/whatever" parameters:nil];
operation.targetObject = nil;
//Does it still exist ? (XCode says an error)
//operation.targetObjectID = nil;
[session.objectManager enqueueObjectRequestOperation:operation];
Thank you in advance for your help.
Using session.objectManager getObjectsAtPathForRouteNamed... is a good option (better than trying to use RKManagedObjectRequestOperation directly).
You need to create another response descriptor, like responseDescriptor, but for places key path and mapping.
Related
I am having an error when trying to map deeply nested objects from JSON with RestKit. First, I try to map hotel name which works normally. However, when I try to get price from "ChargeableRateInfo" from JSON I get following error:
restkit.object_mapping:RKMappingOperation.m:652 WARNING: Failed
mapping nested object: (null)
Here is JSON example which I am trying to map:
{
"HotelListResponse": {
"customerSessionId": "0ABAAA3E-7637-1591-4F62-5548AC792D42",
"numberOfRoomsRequested": 1,
"moreResultsAvailable": true,
"cacheKey": "-48763715:14f65548ac7:2d4e",
"cacheLocation": "10.186.170.62:7300",
"cachedSupplierResponse": {
"#supplierCacheTolerance": "NOT_SUPPORTED",
"#cachedTime": "0",
"#supplierRequestNum": "235",
"#supplierResponseNum": "1",
"#supplierResponseTime": "503",
"#candidatePreptime": "30",
"#otherOverheadTime": "5",
"#tpidUsed": "5001",
"#matchedCurrency": "true",
"#matchedLocale": "true"
},
"HotelList": {
"#size": "1",
"#activePropertyCount": "235",
"HotelSummary": {
"#order": "0",
"#ubsScore": "1069912",
"hotelId": 206005,
"name": "Mediterranean Inn",
"address1": "425 Queen Anne Ave N",
"city": "Seattle",
"stateProvinceCode": "WA",
"postalCode": 98109,
"countryCode": "US",
"airportCode": "SEA",
"supplierType": "E",
"propertyCategory": 1,
"hotelRating": 3,
"confidenceRating": 70,
"amenityMask": 7799051,
"tripAdvisorRating": 4,
"tripAdvisorReviewCount": 1086,
"tripAdvisorRatingUrl": "http://www.tripadvisor.com/img/cdsi/img2/ratings/traveler/4.0-12345-4.gif",
"locationDescription": "Near Pacific Northwest Ballet",
"shortDescription": "<p><b>Property Location</b> <br />With a stay at Mediterranean Inn, you'll be centrally located in Seattle, steps from Key Arena and minutes from Seattle Children's Theatre. This family-friendly",
"highRate": 270,
"lowRate": 162,
"rateCurrencyCode": "USD",
"latitude": 47.62244,
"longitude": -122.35672,
"proximityDistance": 12.288694,
"proximityUnit": "MI",
"hotelInDestination": true,
"thumbNailUrl": "/hotels/1000000/900000/897600/897598/897598_108_t.jpg",
"deepLink": "http://www.travelnow.com/templates/55505/hotels/206005/overview?lang=en¤cy=USD&standardCheckin=9/15/2015&standardCheckout=9/17/2015&roomsCount=1&rooms[0].adultsCount=2",
"RoomRateDetailsList": {
"RoomRateDetails": {
"roomTypeCode": 15567,
"rateCode": 15567,
"maxRoomOccupancy": 2,
"quotedRoomOccupancy": 2,
"minGuestAge": 0,
"roomDescription": "Petite Room, 1 Queen Bed, Kitchenette",
"propertyAvailable": true,
"propertyRestricted": false,
"expediaPropertyId": 897598,
"RateInfos": {
"#size": "1",
"RateInfo": {
"#priceBreakdown": "true",
"#promo": "true",
"#rateChange": "false",
"RoomGroup": {
"Room": {
"numberOfAdults": 2,
"numberOfChildren": 0,
"rateKey": "81423e04-b223-4ea1-807a-8812c13b31be",
"ChargeableNightlyRates": [
{
"#baseRate": "270.00",
"#rate": "162.00",
"#promo": "true"
}, {
"#baseRate": "270.00",
"#rate": "162.00",
"#promo": "true"
}
]
}
},
"ChargeableRateInfo": {
"#averageBaseRate": "270.00",
"#averageRate": "162.00",
"#commissionableUsdTotal": "324.00",
"#currencyCode": "USD",
"#maxNightlyRate": "162.00",
"#nightlyRateTotal": "324.00",
"#grossProfitOffline": "54.87",
"#grossProfitOnline": "81.40",
"#surchargeTotal": "69.07",
"#total": "393.07",
"NightlyRatesPerRoom": {
"#size": "2",
"NightlyRate": [
{
"#baseRate": "270.00",
"#rate": "162.00",
"#promo": "true"
}, {
"#baseRate": "270.00",
"#rate": "162.00",
"#promo": "true"
}
]
},
"Surcharges": {
"#size": "1",
"Surcharge": {
"#type": "TaxAndServiceFee",
"#amount": "69.07"
}
}
},
"nonRefundable": false,
"rateType": "MerchantStandard",
"promoId": 212134483,
"promoDescription": "24 hour deal: save 40%",
"promoType": "Standard",
"currentAllotment": 3
}
}
}
}
}
}
}
}
And here is my code where I try to map this JSON:
- (void)configureRestKit
{
// initialize AFNetworking HTTPClient
NSURL *baseURL = [NSURL URLWithString:#"http://api.ean.com"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
// initialize RestKit
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
// setup object mappings
RKObjectMapping *hotelMapping = [RKObjectMapping mappingForClass:[HotelList class]];
[hotelMapping addAttributeMappingsFromArray:#[#"name"]];
RKObjectMapping *priceMapping = [RKObjectMapping mappingForClass:[ChargeableRateInfo class]];
[priceMapping addAttributeMappingsFromDictionary:#{#"total": #"total"}];
[hotelMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"RoomRateDetailsList.RoomRateDetails.RateInfos.RateInfo.ChargeableRateInfo" toKeyPath:#"chargeableRateInfo" withMapping:priceMapping]];
// register mappings with the provider using a response descriptor
RKResponseDescriptor *responseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:hotelMapping
method:RKRequestMethodGET
pathPattern:#"/ean-services/rs/hotel/v3/list"
keyPath:#"HotelListResponse.HotelList.HotelSummary"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:responseDescriptor];
}
Does anyone know how to solve this? Thanks
The mapping key should be #total based on the content in the JSON.
This isn't ideal however as # is a special character in KVC which RestKit uses heavily. You will need to work around this with something from this answer or this pull request.
i'm new to ios developing and i want to ask how can i post a raw json code to the server.
For Example: i want to send this JSON raw data to http://example.com/user
{
"user":
{
"username": "jkaaannyaad11",
"password": "secret123456",
"gender": "male",
"first_name": "assd",
"last_name": "ffsasd",
"birth_date": "can be null",
"phone_number": "12343234",
"have_car":"1",
"same_gender" :"0",
"uid": "this is id for facebook , can be null"
},
"home":
{
"longitude": "31.380301",
"latitude": "30.054272",
"name": "city"
},
"work":
{
"longitude": "30.068237",
"latitude": "31.024275",
"name": "village"
},
"email":
{
"email_type": "work",
"email": "hello.me#me.com"
}
}
so how can i do it ?
For Example in Android using the JSONObject i can easily oraganize them and then POST them to the website
JSONObject obj = new JSONObject();
JSONObject userObj = new JSONObject();
JSONObject homeObj = new JSONObject();
JSONObject workObj = new JSONObject();
JSONObject emailObj = new JSONObject();
try {
obj.put("user", userObj);
obj.put("home", homeObj);
obj.put("work", workObj);
obj.put("email", emailObj);
homeObj.put("longitude", homePlace.LocationRef.Lng);
homeObj.put("latitude", homePlace.LocationRef.Lat);
homeObj.put("name", homePlace.LocationRef.Address);
Use the AFNetworking library. On the repository page there are many examples including the one below to make a POST request.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"foo": #"bar"};
[manager POST:#"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I have JSON of following kind
{
"Client": {
"FirstName": "String",
"LastName": "String",
"Email": "String",
"Password": "String",
"PhoneNumber": "String",
"Token": "String"
},
"ErrorMessage": "String",
"FriendlyMessage": "String"
}
I know that while mapping if I specify a key path then RestKit matches fields from object specified, in this case Client, to the code I am using for that is as follows
[responseMapping addAttributeMappingsFromDictionary:#{
#"FirstName": #"FirstName",
#"LastName": #"LastName",
#"Email": #"Email",
#"PhoneNumber": #"PhoneNumber",
#"Token": #"Token",
#"Password": #"Password",
#"ErrorMessage": #"ErrorMessage"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
method:RKRequestMethodPOST
pathPattern:nil
keyPath:#"Client"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
But I have two additional fields to map which aren't under client object. How do I map ErrorMessage and FriendlyMessage fields ?
Generally you wouldn't want to map them into your client object, you would want to map them into some other object. You would usually use a different object and response mapping, where the response mapping uses a different key path.
If for some reason you did want them in the same object then you could look at using the #metadata / #parent to get to the parent (https://github.com/RestKit/RestKit/pull/1435).
The API need to pass an array in an url query parameter, how to acheive this in iOS?
I only know how to pass a single vaue, like the API below : ?title=Design Milk&id=feed/http://feeds.feedburner.com/design-milk
API sample:
"title": "Design Milk",
"id": "feed/http://feeds.feedburner.com/design-milk",
"categories": [
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"label": "design"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
"label": "weekly"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
"label": "must reads"
}
]
Create a collection and then use NSJSONSerialization to create JSON data representation. Use the resulting data as the POST data.
NSDictionary *parameters = #{
#"title": #"Design Milk",
#"id": #"feed/http://feeds.feedburner.com/design-milk",
#"categories": #[
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
#"label": #"design"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
#"label": #"weekly"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
#"label": #"must reads"
}
]
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictData options:0 error:&error];
I am using RestKit to map the following JSON to core data.
This is my model:
this is my methods:
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([User class]) inManagedObjectStore:managedObjectStore];
userMapping.identificationAttributes = #[#"id"];
[userMapping addAttributeMappingsFromDictionary:#{
#"birthday":#"birthday",
#"email":#"email",
#"facebook_token":#"facebook_token",
#"first_name":#"first_name",
#"gender":#"gender",
#"interested_in":#"interested_in",
#"last_name":#"last_name",
#"password":#"password",
#"m8_status":#"m8_status",
#"status":#"status",
#"languages": #"languages",
#"hometown":#"hometown",
#"location":#"location",
#"avatar_url":#"avatar_url",
#"mood":#"mood"
}];
RKEntityMapping *findUserMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([FindUser class]) inManagedObjectStore:managedObjectStore];
findUserMapping.identificationAttributes = #[#"id"];
[findUserMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"users" toKeyPath:#"users" withMapping:userMapping]];
[manager addResponseDescriptorsFromArray:#[
[RKResponseDescriptor responseDescriptorWithMapping:findUserMapping
pathPattern:#"/v1/users"
keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]
]];
This is getting objects from example JSON:
{
"users": [
{
"avatar_url": null,
"birthday": "04/11/1984",
"email": "antonina.duminskaya#wildermancruickshank.co.uk", "first_name": "Antonina",
"gender": "female",
"hometown": null,
"id": "5264ee384d61632c4b2f0000",
"interested_in": [
"male",
"female" ],
"languages": [], "last_name": "Duminskaya", "location": null, "m8_status": null,
"mood": null,
"status": null
} ]
}
here:
[objectManager getObjectsAtPath:#"/v1/users" parameters:#{#"session_id":session.id} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
FindUser *findUsers = [[self.fetchedFindUsersResultsController fetchedObjects] lastObject];
NSLog(#"%#", findUsers.users);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
I have message in log:
Relationship 'users' fault on managed object (0x8e964a0) <FindUser: 0x8e964a0> (entity: FindUser; id: 0x8da0790 <x-coredata://083BB731-FDD7-4A35-A174-724F50862A02/FindUser/p1> ; data: {
id = nil;
users = "<relationship fault: 0x8deb260 'users'>";
})
And In mappingResults I have all results about json
Core Data is representing the relationship initially as fault saving memory by not loading all the object graph at once.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/CoreData/Articles/cdFaultingUniquing.html
Also, do not use the reserved word 'id' as the Restkit identification attribute for your managed objects. Try using findUserId and userId and update your mappings accordingly.