How to find dynamic key values in Karate? - karate

I am hitting JIRA API to fetch cycle id based on cycle name
API : http://localhost:8080/rest/zapi/latest/cycle?projectId=78654&versionId=123
and I am getting following response:
{
"1345": {
"totalExecutions": 0,
"endDate": "",
"description": "",
"versionName": "Unscheduled",
"projectKey": "ABC",
"totalDefects": 0,
"versionId": 123,
"name": "First cycle",
"totalFolders": 0,
"projectId": 78654
},
"5789": {
"totalExecutions": 0,
"endDate": "",
"description": "",
"versionName": "Unscheduled",
"projectKey": "ABC",
"totalDefects": 0,
"versionId": 123,
"name": "Karate DEMO",
"totalFolders": 0,
"projectId": 78654
},
"6543": {
"totalExecutions": 0,
"endDate": "",
"description": "",
"versionName": "Unscheduled",
"projectKey": "ABC",
"totalDefects": 0,
"versionId": 123,
"name": "Second Cycle",
"totalFolders": 0,
"projectId": 78654
},
"recordsCount": 3
}
Here Id's are dynamic i.e. 1345,5789,6543
How do I fetch Id i.e. 5789 where name is "Karate DEMO" using karate jsonpath

Use a JSON transform to change the shape which makes it easier to do JsonPath. You can also find data because karate.forEach() is a "scan": https://github.com/intuit/karate#json-transforms
* def list = []
* def fun = function(k, v){ karate.appendTo('list', { key: k, val: v } )}
* karate.forEach(response, fun)
* def keys = $list[?(#.val.name=='Karate DEMO')].key

Related

Powershell Json object from object

I have a method that returns a Json object from a query using the FOR JOSN PATH approach.
Example:
SELECT State, COUNT(*) AS Items
FROM dbo.States
WHERE SomeFilterColumn = #FilterParam
GROUP BY State
FOR JSON PATH
This returns
[
{
"State": "Pending",
"Items": 23
},
{
"State": "Finished",
"Items", 7736
}
]
I also have a function in Powershell that returns the result. However I have issues how it is returned.
function Get-Json-From-Query {
param(
[Int32]$filterParam
)
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
...
$SqlCmd = $SqlConnection.CreateCommand();
$SqlCmd.CommandText = $Query #The query shown above
$SqlCmd.Parameters.Add("#FilterParam", $filterParam);
$SqlCmd.ExecuteScalar()
}
However I do not know how to get the result of my query properly added to a JSON value.
I tried many things like:
#{
States = (Get-Json-From-Query -filterParam 1234)
}
However this gives me also the param information which I do not want:
Expecting
{ "States": [... The Array show above ... ] }
Actual
{
"States": [
{
"CompareInfo": 0,
"XmlSchemaCollectionDatabase": "",
"XmlSchemaCollectionOwningSchema": "",
"XmlSchemaCollectionName": "",
"ForceColumnEncryption": false,
"DbType": 11,
"LocaleId": 0,
"ParameterName": "#FilterParam",
"Precision": 0,
"Scale": 0,
"SqlDbType": 8,
"SqlValue": "1234",
"UdtTypeName": "",
"TypeName": "",
"Value": 1234,
"Direction": 1,
"IsNullable": false,
"Offset": 0,
"Size": 0,
"SourceColumn": "",
"SourceColumnNullMapping": false,
"SourceVersion": 512
},
"[{\"State\":\"Pending\",\"Items\":23},{\"State\":\"Finished\",\"Items\":7763}]"
]
}
How do I get the right data in my Json object?

Karate - To find array indices of multiple occurance of an element in a JSON response array

I have a JSON response from an endpoint that gives me a nested array of elements. And given an input value, I want to find out all the index values where this value occurs and not just the first occurance of the element.
For example here is the response I have:
{
"items": [
{
"vin": "MMTestingVIN00002",
"dealerCode": "1",
"nmscCode": "1",
"warning": {
"warningLightType": {
"code": 1,
"description": "",
"symbol": "OLW",
"type": "S",
"priority": "1"
}
}
},
{
"vin": "HESQM0IBWUR7DH0DU",
"dealerCode": "1",
"nmscCode": "1",
"warning": {
"warningLightType": {
"code": 1,
"description": "",
"symbol": "OLW",
"type": "S",
"priority": "1"
}
}
},
{
"vin": "MMTestingVIN00002",
"dealerCode": "1",
"nmscCode": "1",
"warning": {
"warningLightType": {
"code": 1,
"description": "",
"symbol": "OLW",
"type": "S",
"priority": "1"
}
}
},
{
"vin": "ZCADWKEQM1GEADEQR",
"dealerCode": "1",
"nmscCode": "1",
"warning": {
"warningLightType": {
"code": 1,
"description": "",
"symbol": "WASH",
"type": "S",
"priority": "1"
}
}
},
{
"vin": "H5QGE06R54B8KYOUV",
"dealerCode": "1",
"nmscCode": "1",
"warning": {
"warningLightType": {
"code": 1,
"description": "",
"symbol": "WASH",
"type": "S",
"priority": "1"
}
}
}
]
}
I want to find out the indices where the arrays with "vin = MMTestingVIN00002" occurs.
I looked at https://github.com/intuit/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/js-arrays.feature for ideas. Also looked at other SO answers and tried:
* def VIN = 'MMTestingVIN00002'
* def response = result.items
* def names = $[*].vin
* def index = names.indexOf(VIN)
* print index
This gives the only the first occurance with the index 0. Ideally I want a result array index[] which gives [0,2] as result.
Here you go:
* def indexes = []
* def fun = function(x, i){ if (x.vin == 'MMTestingVIN00002') karate.appendTo(indexes, i) }
* karate.forEach(response.items, fun)

Zapier to create multiple rows in Google Sheet from Tsheets data

In a Zapier Zap I am using an an API GET call to Tsheets to grab a list of Timesheets. I would like to split out each time sheet into line items like line items in a Xero invoice because I would like to save item data from each timesheet to its own row in a Google sheet. (Ideally I would like to save the line data directly to a MySQL database but I see that Zapier currently only support Google sheets saving multiple lines at a time.) However I am having no joy.
I suspect one of two issues:
Zapier expects the word lineitems in the response or
The format of the response is not correct - I seem to have two "results" categories
In my step to Set up Google Sheets Spreadsheet Row I don't get a selection of comma separated items as shown in the example shown on the picture here:
Add an action app that supports line items, and each item will be saved individually
The image is from this page: https://zapier.com/blog/formatter-line-item-automation/ with the caption "Add an action app that supports line items, and each item will be saved individually" For what I get see photo https://cdn.zapier.com/storage/photos/f055dcf11a4b11b86f912f9032780429.png
In the step that returns the data from the API the text response is shown in https://cdn.zapier.com/storage/photos/33129fb7425cfae44be4a81533d6e892.png
and if I return json data it is like this: https://cdn.zapier.com/storage/photos/34da1b98f8941324c35befef8efe350d.png
Can anyone confirm that my suspicions are correct and whether 1 or 2 is the likely culprit.
Is it possible this link Zapier - Catch Hook - JSON Array - Loop over each item in array will lead me to the solution? It looks like it may but I don't see exactly how the writer incorporated it in to his Zap.
Edit: My data returned from the API looks like this:
{
"results": {
"timesheets": {
"11515534": {
"id": 11515534,
"user_id": 1260679,
"jobcode_id": 11974818,
"start": "2018-07-13T14:58:00+10:00",
"end": "2018-07-13T14:58:00+10:00",
"duration": 0,
"date": "2018-07-13",
"tz": 10,
"tz_str": "Australia\/Brisbane",
"type": "regular",
"location": "(Brisbane, Queensland, AU?)",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"118516": "",
"121680": "",
"118530": "",
"118518": "Field supplies, materials"
},
"last_modified": "2018-07-13T04:59:27+00:00",
"attached_files": [
]
},
"11515652": {
"id": 11515652,
"user_id": 1260679,
"jobcode_id": 11974830,
"start": "2018-07-13T14:59:00+10:00",
"end": "2018-07-13T14:59:00+10:00",
"duration": 0,
"date": "2018-07-13",
"tz": 10,
"tz_str": "Australia\/Brisbane",
"type": "regular",
"location": "(Brisbane, Queensland, AU?)",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"118516": "",
"121680": "",
"118530": ""
},
"last_modified": "2018-07-13T05:00:30+00:00",
"attached_files": [
]
},
"39799840": {
"id": 39799840,
"user_id": 1260679,
"jobcode_id": 19280104,
"start": "2018-10-24T11:45:00+11:00",
"end": "2018-10-24T12:00:00+11:00",
"duration": 900,
"date": "2018-10-24",
"tz": 11,
"tz_str": "Australia\/Brisbane",
"type": "regular",
"location": "(Sydney, New South Wales, AU?)",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"118516": "",
"121680": "FP - Field plant Installation",
"118530": "Site cleanup"
},
"last_modified": "2018-10-24T05:56:27+00:00",
"attached_files": [
]
},
"39801850": {
"id": 39801850,
"user_id": 1260679,
"jobcode_id": 19280204,
"start": "2018-10-24T12:00:00+11:00",
"end": "2018-10-24T13:45:00+11:00",
"duration": 6300,
"date": "2018-10-24",
"tz": 11,
"tz_str": "Australia\/Brisbane",
"type": "regular",
"location": "(Sydney, New South Wales, AU?)",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"118516": "",
"121680": "OP - Plant, Vehicles",
"118530": "Load\/Unload"
},
"last_modified": "2018-10-24T05:57:04+00:00",
"attached_files": [
]
},
"40192757": {
"id": 40192757,
"user_id": 1260679,
"jobcode_id": 19280110,
"start": "2018-10-25T08:00:00+11:00",
"end": "2018-10-25T10:00:00+11:00",
"duration": 7200,
"date": "2018-10-25",
"tz": 11,
"tz_str": "Australia\/Brisbane",
"type": "regular",
"location": "TSheets Android App",
"on_the_clock": false,
"locked": 0,
"notes": "From my mobile",
"customfields": {
"118516": "",
"121680": "FW - Plant Assembly",
"118530": "Panels"
},
"last_modified": "2018-10-24T23:02:56+00:00",
"attached_files": [
]
},
"40193033": {
"id": 40193033,
"user_id": 1260679,
"jobcode_id": 19280108,
"start": "2018-10-25T10:00:00+11:00",
"end": "2018-10-25T10:00:00+11:00",
"duration": 0,
"date": "2018-10-25",
"tz": 11,
"tz_str": "Australia\/Brisbane",
"type": "regular",
"location": "TSheets Android App",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"118516": "",
"121680": "FW - Plant Assembly",
"118530": "Panels"
},
"last_modified": "2018-10-24T23:06:05+00:00",
"attached_files": [
]
}
}
},
"more": false
}
And this is my Python code: https://imgur.com/a/8W1X1em
Alright so I think I've worked something out for you. The example you provided Zapier - Catch Hook - JSON Array - Loop over each item in array is definitely on the right track, but, because it relies on webhooks, it probably won't work for you unless you can POST the data from your invoicing application.
Note: I code in Python so my examples will be in Python, that said these examples are pretty much code agnostic and can be replicated in Javascript as well.
I setup a dummy Zap to replicate what is happening with your zap currently
# results = requests.get(url, headers=header)
# results = results.json()
# Dummy result data converted to JSON object after API GET request:
results = {
"results" : {
"timesheets" : {
"timesheet_id_1" : {
"data_1" : "data",
"data_2" : "data",
"data_3" : "data"
},
"timesheet_id_2" : {
"data_1" : "data",
"data_2" : "data",
"data_3" : "data"
},
"timesheet_id_3" : {
"data_1" : "data",
"data_2" : "data",
"data_3" : "data"
}
}
}
}
return results
Reading a bit further here in order for Zapier to map line items it needs to receive the data in an array. The above output is a dictionary object, Zapier does map the values in this dictionary to data that can be accessed later, however it maps the entire dictionary which is why you are seeing the output as multiple fields and as is replicated in my output. What you are looking to do is map a subset of the dictionary AND provide each subset as separate outputs.
What you will want to do is loop through the inner fields of the results dictionary object and execute zaps on the nested "timesheet_id_n". To do so we will have to return a list of line items, as stated above line items must be placed into an array. And so my code to achieve this looks like:
# results = requests.get(url, headers=header)
# results = results.json()
# Dummy result data converted to JSON object after API GET request:
results = {
"results" : {
"timesheets" : {
"timesheet_id_1" : {
"data_1" : "data",
"data_2" : "data",
"data_3" : "data"
},
"timesheet_id_2" : {
"data_1" : "data",
"data_2" : "data",
"data_3" : "data"
},
"timesheet_id_3" : {
"data_1" : "data",
"data_2" : "data",
"data_3" : "data"
}
}
}
}
# Container for my line items. Each element in this list will be executed on separately
return_results = []
results = results.get("results")
results = results.get("timesheets")
for item in results:
return_results.append({"sheet_id" : item, "sheet_data" : results.get(item)})
return return_results
The output of return_results will be an array of dictionary objects. As these dictionary objects are in array Zapier will treat them as line items, additionally because each line item is a dictionary object Zapier will automatically map each value so that they can be independently be used in later action steps. You can see this demonstrated in the output of my trigger zap in the following screenshots:
output 1
output 2
output 3
Hope this helped!

How to know whether a email address exists on Elasticsearch?

So I have added some data (email address with name) on elasticsearch . Now want to verify a particular email address is exists or not .
Below is the code which I have Executed via Postman :
**URL :** localhost:9200/demo1/demo_emails/_bulk (Put request)
**Raw Data (json) :**
{ "create" : { "_index" : "demo1", "_type" : "Supp_emails", "_id" : "2" } }
{ "name" : "x1", "email": "x1#r.com" }
{ "create" : { "_index" : "demo1", "_type" : "Supp_emails", "_id" : "3" } }
{ "name" : "x2", "email": "x2#r.com" }
You can see "demo1" is the Index & "demo_emails" is the field type . And I have added two email address on that index.
Now want to verify whether 'x1#r.com' is exist or not ?
I have tried the below query, but its showing all details instead of one email
**URL :** localhost:9200/demo1/Supp_emails/_search?q=email:x1#r.com (Get request)
**Output :**
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.87546873,
"hits": [
{
"_index": "demo1",
"_type": "demo_emails",
"_id": "1",
"_score": 0.87546873,
"_source": {
"name": "x1",
"email": "x1#r.com"
}
},
{
"_index": "demo1",
"_type": "demo_emails",
"_id": "2",
"_score": 0.87546873,
"_source": {
"name": "x2",
"email": "x2#r.com"
}
}
When you search for email:x1#r.com the tokenizer breaks up the string into tokens. These tokens depend on which analyzer and tokenizer you've used.
I'm assuming you didn't do any fancy analysis, so these tokens would be :
GET index/_analyze
{
"tokens": [
{
"token": "x1",
"start_offset": 0,
"end_offset": 2,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "r.com",
"start_offset": 3,
"end_offset": 8,
"type": "<ALPHANUM>",
"position": 1
}
]
}
If you take a look at the documentation of query_string you'll find that default operator is OR
So your query actually looks for x1 OR r.com, this is why both of these documents return.
You can see this by adding the parameter http://elastic...?q=...&explain=true.
How do you solve this issue? Use a different operator. Just change the default operator to AND, d http://elastic...?q=...&default_operator=true
Useful links:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-explain.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.2/indices-analyze.html

Restify very simple JSONClient returns empty json

I just started using restify and tries to build a very simple JSONClient and fails on the first step.
var restify = require('restify');
var client = restify.createJsonClient({
url: 'http://api.bgm.tv'
});
client.get('/calendar', function(err, req, res, obj) {
console.log('%j', obj);
});
This pieces of code returns {} with a status code 200
If you check http://api.bgm.tv/calendar in browser or curl it seems to be a legit json GET Rest API and does not require auth or anything else.
I tried other API such as stackoverflow api it works perfectly, so I assume something wrong with the server side?
If anyone can try to run it and help me point out what might went wrong would be very appreciated.
I runned your example node code and got a proper response (the same you get when browsing).
You probably have some version problem or a console.log size limitation.
Try using: console.log(obj[0]); it should print only the first object in the json.
I'm using node v0.8.9 and restify v2.4.1 on a mac.
Yeah, when I use the Postman plugin for Chrome and do a GET request to http://api.bgm.tv/calendar I get:
[
{
"weekday": {
"en": "Mon",
"cn": "星期一",
"ja": "月耀日",
"id": 1
},
"items": [
{
"id": 46458,
"url": "http://bgm.tv/subject/46458",
"type": 0,
"name": "アイカツ! -アイドルカツドウ!-",
"name_cn": "偶像活动",
"summary": "",
"eps": 0,
"air_date": "2012-10-08",
"air_weekday": 1,
"images": {
"large": "http://lain.bgm.tv/pic/cover/l/db/7f/46458_8mM39.jpg",
"common": "http://lain.bgm.tv/pic/cover/c/db/7f/46458_8mM39.jpg",
"medium": "http://lain.bgm.tv/pic/cover/m/db/7f/46458_8mM39.jpg",
"small": "http://lain.bgm.tv/pic/cover/s/db/7f/46458_8mM39.jpg",
"grid": "http://lain.bgm.tv/pic/cover/g/db/7f/46458_8mM39.jpg"
},
"collection": {
"wish": 0,
"collect": 0,
"doing": 44,
"on_hold": 0,
"dropped": 0
}
},
{
"id": 57150,
"url": "http://bgm.tv/subject/57150",
"type": 0,
"name": "LINE OFFLINE ~サラリーマン~",
"name_cn": "离线LINE - 上班族 -",
"summary": "",
"eps": 0,
"air_date": "2013-01-07",
"air_weekday": 1,
"images": {
"large": "http://lain.bgm.tv/pic/cover/l/71/28/57150_Kz171.jpg",
"common": "http://lain.bgm.tv/pic/cover/c/71/28/57150_Kz171.jpg",
"medium": "http://lain.bgm.tv/pic/cover/m/71/28/57150_Kz171.jpg",
"small": "http://lain.bgm.tv/pic/cover/s/71/28/57150_Kz171.jpg",
"grid": "http://lain.bgm.tv/pic/cover/g/71/28/57150_Kz171.jpg"
},
"collection": {
"wish": 0,
"collect": 0,
"doing": 206,
"on_hold": 0,
"dropped": 0
}
},
{
"id": 58709,
"url": "http://bgm.tv/subject/58709",
"type": 0,
"name": "ハヤテのごとく! Cuties",
"name_cn": "旋风管家 Cuties",
"summary": "",
"eps": 0,
"air_date": "2013-04-08",
"air_weekday": 1,
"images": {
"large": "http://lain.bgm.tv/pic/cover/l/15/28/58709_H7uj8.jpg",
"common": "http://lain.bgm.tv/pic/cover/c/15/28/58709_H7uj8.jpg",
"medium": "http://lain.bgm.tv/pic/cover/m/15/28/58709_H7uj8.jpg",
"small": "http://lain.bgm.tv/pic/cover/s/15/28/58709_H7uj8.jpg",
"grid": "http://lain.bgm.tv/pic/cover/g/15/28/58709_H7uj8.jpg"
},
"collection": {
"wish": 0,
"collect": 0,
"doing": 219,
"on_hold": 0,
"dropped": 0
}
},
...and a bunch more, but the body limit to answers on SO is 30,000 characters.