I have two JSONs, which are looking like:
{
"749": {
"email": "myMail#me.com",
"firstname": "Mr",
"lastname": "Smith"
}
}
and
[
{
"entity_id": "1",
"city": "myCity",
"country_id": "UA",
"region": null,
"postcode": "001",
"telephone": "+38000000001",
"fax": null,
"street": [
"myStrit ",
"12"
],
"is_default_billing": 1,
"is_default_shipping": 0
},
{
"entity_id": "2",
"city": "myCity",
"country_id": "UA",
"region": null,
"postcode": "001",
"telephone": "+3800000002",
"fax": null,
"street": [
"myStrit2",
"33"
],
"is_default_billing": 0,
"is_default_shipping": 1
}
]
Path for getting first JSON is mySite/customers, and for the second is mySite/customers/:userId/addresses.
where userId is unnamed attribute from first JSON (749 in my example).
I am new in RestKit and I can't really figure out, how to map it by one request...
PS: I get these JSONs from Magento rest api.
You say nothing about what you're trying to map into, but.
For the first JSON, you need to use addAttributeMappingFromKeyOfRepresentationToAttribute on the mapping to extract the 749 value and use it as a key at the same time.
For the second JSON there doesn't appear to be any connection to the first so you need to try mapping that and come back with specific issues. See this page for guidance.
RestKit expects each object to be described by a dictionary which can be processed by the mapper. Your service does not return an array of objects, though, rather a dictionary of dictionaries, which RestKit cannot correctly interpret as a collection of objects it can map individually. Of course, the problem would disappear if your service could return an array of dictionaries instead.
Fortunately, there is a way to transform the dictionary of dictionaries you receive into an array of dictionaries right before the mapper is called. This is achieved by setting a conversion block via -[RKObjectRequestOperation setWillMapDeserializedResponseBlock:].
The block receives the result of the initial parsing (here the dictionary of dictionaries), which you can easily turn into an array of dictionaries by calling -[NSDictionary allValues]:
RKManagedObjectStore *managedObjectStore = ...;
RKResponseDescriptor *responseDescriptor = ...;
NSURLRequest *request = ...;
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[responseDescriptor]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
[managedObjectRequestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) {
return [deserializedResponseBody allValues];
}];
[[NSOperationQueue currentQueue] addOperation:managedObjectRequestOperation];
Related
I have a use case where I want to assert on a API response and compare it with the csv data.
Step1:
Csv file: *test.csv*
id,date,fullname,cost,country,code
1,02-03-2002,user1,$200,Canada,CAN
2, 04-05-2016,user2,$1500,United States, USA
I read the csv file and store it in a variable
def var1 = read(test.csv)
So now, var1 is a list of jsons based on my csv
var1 = [
{
"id":1,
"date":"02-03-2002",
"fullname": "user1",
"cost": "$200",
"country": "Canada",
"code": "CAN"
},
{
"id":2,
"date":"04-05-2016",
"fullname": "user2",
"cost": "$1500",
"country": "United States",
"code": "USA"
}
]
Step2:
I hit my api and get a response
Given url "https://dummyurl.com
Given path "/userdetails"
When method get
Then status 200
* def apiResponse = response
Step 3:
My api returns a list response which is:
{
"id":1,
"date":"02-03-2002",
"fullname": "user1",
"cost": "$200",
"country": {
"name": "Canada",
"code": "CAN"
}
},
{
"id":2,
"date":"05-04-2012",
"fullname": "user2",
"cost": "$1500",
"country": {
"name": "United States",
"code": "USA"
}
},
...and more 100 records..
]
Step 4:
So there are two assertions now which I wanted to perform
Get the count of csvresponse and apiresponse and compare which I did using the .length operator
Secondly, I want to confirm if each csv records are matching with each api response.
And if possible in my case id key from csv and apiresponse is primary key, so if I can iterate on id and match the api response for any discrepancy.
Let me know if this is readable for you and if I was able to explain my use case.
Thanks for your earlier response.
Please read up on the match contains syntax, that's all you need: https://github.com/intuit/karate#match-contains
So this one line should be enough:
* match var1 contains response
Also look at this answer in case the new contains deep helps: https://stackoverflow.com/a/63103746/143475
Try to avoid iterating, it is not needed for most API tests. But you can certainly do it. Look at these answers:
https://stackoverflow.com/a/62567262/143475
Also read this - because I suspect you are trying to over-complicate your tests. Please don't. Write tests where your are 100% sure of the "shape" of the response as far as possible: https://stackoverflow.com/a/54126724/143475
And please please read the docs. It is worth it.
I have a 3rd party application which stored the data in the below format, I haven't seen any such format before
A<1,?,'clientID'=?,'displayType'='show','firstName'='First','id'=1234567,'info'=A<1,?,'acceptUser'=48141315,'nodeID'=1234567,'shareUser'=63490234>,'lastName'='Last','shareOwner'=63490234,'subtype'='shareaccepted','toUser'=48141315,'type'='notification','userID'=48141315,'username'='lastFirst'>
Might be a custom format. They should be telling you what format it is, you shouldn't have to guess, it should be documented somewhere.
So first thing you should do is ask them.
Now, if you indent it, it looks pretty straightforward. A<...> seems to define an object.
A<
1,
?,
'clientID'=?,
'displayType'='show',
'firstName'='First',
'id'=1234567,
'info'=A<
1,
?,
'acceptUser'=48141315,
'nodeID'=1234567,
'shareUser'=63490234
>,
'lastName'='Last',
'shareOwner'=63490234,
'subtype'='shareaccepted',
'toUser'=48141315,
'type'='notification',
'userID'=48141315,
'username'='lastFirst'
>
Unless this is a known format, I am afraid you will have to parse it yourself.
An other way could be to manually translate it to Json (with a custom class of your own) and then use Gson or Jackson to parse it to POJOs.
A JSON equivalent would be
{
"v1": 1,
"v2": "?",
"clientID": "?",
"displayType": "show",
"firstName": "First",
"id": 1234567,
"info": {
"v1": 1,
"v2": "?",
"acceptUser": 48141315,
"nodeID": 1234567,
"shareUser": 63490234
},
"lastName": "Last",
"shareOwner": 63490234,
"subtype": "shareaccepted",
"toUser": 48141315,
"type": "notification",
"userID": 48141315,
"username": "lastFirst"
}
I am representing JSON objects in Redis by flattening the JSON path keys like so:
JSON object
{
"users": [
{
"name": "John Smith",
"address": {
"street": "12 Rainbow Avenue",
"country": "Fuzzyland"
}
}, {
"name": "Billy Bob",
"address": {
"street": "8 Rocky Lane",
"country": "Fraggleville"
}
}
]
}
Redis entries
users // SET [0, 1]
users:0 // SET [name, address]
users:0:name // STRING "John Smith"
users:0:address // SET [street, country]
users:0:address:street // STRING "12 Rainbow Avenue"
users:0:address:country // STRING "Fuzzyland"
users:1 // SET [name, address]
users:1:name // STRING "Billy Bob"
users:1:address // SET [street, country]
users:1:address:street // STRING "8 Rocky Lane"
users:1:address:country // STRING "Fraggleville"
As you can see, for properties that are arrays or object literals I am using a Redis SET to store the available keys.
It is easy enough for me to convert the JSON object to this structure using Node. However I am not experienced enough with Redis to write recursive queries that stitch together a complex result.
For example, say I want to get all the keys and values for users:1. How do I write a query that looks at the value of users:1 sees that it is a SET so uses the values from that as another set of query keys?
From a form submission I receive two objects: the original values and the dirty values. I like to figure out how to create a diff to send to the server using the following rules:
id field of the root object should always be included
all changed primitive values should be included
all nested changes should be included as well.
if a nested value other than id changed, it should include id as well.
Original values:
{
"id":10,
"name": "tkvw"
"locale": "nl",
"address":{
"id":2,
"street": "Somewhere",
"zipcode": "8965",
},
"subscriptions":[8,9,10],
"category":{
"id":6
},
}
Example expected diff objects:
1) User changes field name to "Foo"
{
"id":10,
"name":"foo"
}
2) User changes field street on address node and category
{
"id":10,
"address":{
"id": 2,
"street":"Changed"
},
"category":{
"id":5
}
}
I do understand the basics of functional programming, but I just need a hint in the right direction (some meta code maybe).
Take a look at JSON Patch (rfc6902), JSON Patch is a format for describing changes to a JSON document. For example:
[
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
]
You generate a patch by comparing to JS objects/arrays, and then you can apply the patch to the original object (on the server side for example) to reflect changes.
You can create a patch using the fast-json-patch lib.
const obj1 = {"id":10,"name":"tkvw","locale":"nl","address":{"id":2,"street":"Somewhere","zipcode":"8965"},"subscriptions":[8,9,10],"category":{"id":6}};
const obj2 = {"id":10,"name":"cats","locale":"nl","address":{"id":2,"street":"Somewhere","zipcode":"8965"},"subscriptions":[8,9,10,11],"category":{"id":7}};
const delta = jsonpatch.compare(obj1, obj2);
console.log('delta:\n', delta);
const doc = jsonpatch.applyPatch(obj1, delta).newDocument;
console.log('patched obj1:\n', doc);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-json-patch/2.0.6/fast-json-patch.min.js"></script>
I get this json response calling a REST api:
{
"ProfileResponse": {
"Request_timestamp": 1378473780145780000,
"Execution_time": 30135057
},
"Results": {
"newsession": {
"Sessionid": "110873298014",
"Status": "ACTIVE",
"Tag": "GO",
"TimeStamp": 1378473780146026000
}
},
"ResultsCount": 0,
"ResultsURL": ""
}
and I want to parse this response and get the newsession into a session object that have defined as an objective-c class.
I have defined a base_mapping that maps the base fields ('PrifileResponse', 'Results', 'ResultsCount', 'ResultsURL'), and another mapping for the 'newsession' and a relationship mapping:
RKObjectMapping *baseResponseMapping = [RKObjectMapping mappingForClass:[CSBaseResponse class]];
RKObjectMapping *sessionMapping = [RKObjectMapping mappingForClass:[CSSessionResponse class]];
[sessionMapping addAttributeMappingsFromDictionary:#{
#"Sessionid": #"sessionid",
#"Status": #"status"
}
];
RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:#"Results" toKeyPath:#"results" withMapping:sessionMapping];
[baseResponseMapping addPropertyMapping:relationshipMapping];
but I can't access the "newsession",
my question specifically is, is there a syntax that I can use in the "from key path" like Results.newsession or something like that to access the inside of "newsession",
or what is the best practice to parse/map this nested structure?