Elixir HTTPoisin.get avoid dedup in response data - duplicates

I am making call to HTTP Rest API in elixir
url = "http://localhost:8080/getScoreData"
case HTTPoison.get(url) do
{:ok, %{status_code: 200, body: body}} ->
Logger.info("body is #{inspect(body)}")
overall_score = Jason.decode!(body, as: [%OverallScore{}])
{:ok, overall_score}
end
which in the web browser returns
{
"avgPass": 85.55,
"avgFail": 14.45,
"totalStudents": 80.0,
"myScoreSchema": [
{
"average": 80.0,
"count": 8.0,
"percent": 80.0,
"name": "John"
},
{
"average": 0.0,
"count": 0.0,
"percent": 0.0,
"name": "Cena"
},
{
"average": 0.0,
"count": 0.0,
"percent": 0.0,
"name": "Sunny"
},
{
"average": 0.0,
"count": 0.0,
"percent": 0.0,
"name": "Michael"
}
]
}
but the log as of the line Logger.info("body is #{inspect(body)}") from above code dedups
the data and returns below data instead
{
"avgPass": 85.55,
"avgFail": 14.45,
"totalStudents": 80.0,
"myScoreSchema": [
{
"average": 80.0,
"count": 8.0,
"percent": 80.0,
"name": "John"
},
{
"average": 0.0,
"count": 0.0,
"percent": 0.0,
"name": "Cena Sunny Michael"
}
]
}
Even though this is a smart feature but I don't want this dedup feature. How to avoid the dedup.

To eliminate whether or not HTTPoison is really deduping or not, you can use elixir to get the raw response back first:
defmodule Testmodule.HttpClient do
def send_request(request, callback_host, callback_port) when is_integer(callback_port) do
# Convert to charlist, as that's what the erlang function is expecting.
some_host_in_net = callback_host |> String.to_charlist
{:ok, socket} =
:gen_tcp.connect(some_host_in_net, callback_port, [:binary, packet: :raw, active: false])
:ok = :gen_tcp.send(socket, request)
# Check response status
case :gen_tcp.recv(socket, 0) do
{:ok, response} -> :ok = :gen_tcp.close(socket)
response
{:error, :closed} -> IO.puts "Something went wrong."
end
end
end
Define your test request with:
def request_pool do
"""
GET /getScoreData HTTP/1.1
Host: localhost
User-Agent: ExampleBrowser/1.0
Accept: */*
messagebody here
"""
end
And finally, you can use Elixir/Erlang to call your endpoint:
Testmodule.HttpClient.send_request(request, "127.0.0.1", 8080)
This should get you what you're seeing in the browser, at which point you can parse it however your heart desires.
But as soon as you try to convert it using Poison.decode, keep in mind that it likely will dedupe your data, as it might treat duplicated keys as updates to the values, rather than allowing duplicate keys to exist in a map.

Related

XTB API JSON cannot modify existing trade position

I am using a xAPI Playground for testing, link here:
https://playground.xapi.pro/
I want to edit/modify existing position with command: tradeTransaction
Documentation says to modify existing position I should use "type" as 3 and "cmd" should match existing position (0 for BUY and 1 for SELL)
{
"command": "tradeTransaction",
"arguments": {
"tradeTransInfo": {
"cmd": 1,
"customComment": "Some text",
"expiration": 0,
"order": order_number_as_int ,
"price": open_price_as_double,
"sl": my_double_value,
"tp": my_another_double_value,
"symbol": "f.e. OIL.WTI",
"type": 3,
"volume": 0.01
}
}
}
Error code
{
"status": false,
"errorCode": "SE199",
"errorDescr": "Internal error"
}
All possible data collected from API about existing position:
{'cmd': 1, 'order': 474325736, 'digits': 2, 'offset': 0, 'order2': 474325838, 'position': 474325736, 'symbol': 'OIL.WTI', 'comment': '', 'customComment': '', 'commission': 0.0, 'storage': 0.0, 'margin_rate': 0.0, 'close_price': 76.65, 'open_price': 76.57, 'nominalValue': 0.0, 'profit': -3.56, 'volume': 0.01, 'sl': 80.0, 'tp': 70.0, 'closed': False, 'timestamp': 1676665564666, 'spread': 0, 'taxes': 0.0, 'open_time': 1676663063081, 'open_timeString': 'Fri Feb 17 20:44:23 CET 2023', 'close_time': None, 'close_timeString': None, 'expiration': None, 'expirationString': None},
API documentation is here:
http://developers.xstore.pro/documentation/#tradeTransaction
Ofc I tried every possible value in "cmd" and "type" but it does not help.
Error code sometimes are diffrent, f. e:
{
"command": "tradeTransaction",
"arguments": {
"tradeTransInfo": {
"cmd": 3,
"customComment": "Some text",
"expiration": 0,
"order": 474325838,
"price": 0,
"sl": 0,
"tp": 0,
"symbol": "OIL.WTI",
"type": 3,
"volume": 0.01
}
}
}
Error code:
{
"status": false,
"errorCode": "BE4",
"errorDescr": "remaining nominal must be greater than zero"
}
Any ideas what I can do wrong?
I am in touch with XTB support, still waiting for response.
Thanks in advance for any help!

I need to compare 2 JSON files in PYTHON with transferring the result to a separate file

I have 2 JSON-files and I need to compare them.
json_new.json
{"company_id": 111111, "resource": "record", "resource_id": 406155061, "status": "create", "data": {"id": 11111111, "company_id": 111111, "services": [{"id": 22222225, "title": "\u0421\u0442\u0440\u0438\u0436\u043a\u0430", "cost": 1500, "cost_per_unit": 1500, "first_cost": 1500, "amount": 1}], "goods_transactions": [], "staff": {"id": 1819441, "name": "\u041c\u0430\u0441\u0442\u0435\u0440"}, "client": {"id": 130345867, "name": "\u041a\u043b\u0438\u0435\u043d\u0442", "phone": "79111111111", "success_visits_count": 2, "fail_visits_count": 0}, "clients_count": 1, "datetime": "2022-01-25T13:00:00+03:00", "create_date": "2022-01-22T00:54:00+03:00", "online": false, "attendance": 2, "confirmed": 1, "seance_length": 3600, "length": 3600, "master_request": 1, "visit_id": 346427049, "created_user_id": 10573443, "deleted": false, "paid_full": 1, "last_change_date": "2022-01-22T00:54:00+03:00", "record_labels": "", "date": "2022-01-22 10:00:00"}}
json_old.json
{"company_id": 111111, "resource": "record", "resource_id": 406155061, "status": "create", "data": {"id": 11111111, "company_id": 111111, "services": [{"id": 9035445, "title": "\u0421\u0442\u0440\u0438\u0436\u043a\u0430", "cost": 1500, "cost_per_unit": 1500, "first_cost": 1500, "amount": 1}], "goods_transactions": [], "staff": {"id": 1819441, "name": "\u041c\u0430\u0441\u0442\u0435\u0440"}, "client": {"id": 130345867, "name": "\u041a\u043b\u0438\u0435\u043d\u0442", "phone": "79111111111", "success_visits_count": 2, "fail_visits_count": 0}, "clients_count": 1, "datetime": "2022-01-25T11:00:00+03:00", "create_date": "2022-01-22T00:54:00+03:00", "online": false, "attendance": 0, "confirmed": 1, "seance_length": 3600, "length": 3600, "master_request": 1, "visit_id": 346427049, "created_user_id": 10573443, "deleted": false, "paid_full": 0, "last_change_date": "2022-01-22T00:54:00+03:00", "record_labels": "", "date": "2022-01-22 10:00:00"}}
In these files, you need to compare the individual parts specified in diff_list:
diff_list = ["services", "staff", "datetime"]
Also code should print result in console, copy and transfer result copy to the file called result.json
My code
import data as data
import json
# JSON string
with open('json_old.json') as json_1:
json1_dict = json.load(json_1)
with open('json_new.json') as json_2:
json2_dict = json.load(json_2)
diff_list = ["services", "staff", "datetime"]
result = [
(sorted(json1_dict.items())),
(sorted(json2_dict.items()))
]
print(sorted(json1_dict.items()) == sorted(json2_dict.items()))
with open('result.json', 'w') as f:
json.dump(result, f)
This code is actually works but I need to catch the change of certain parameters specified in diff_list and output the value: what has changed and for what.
Thank you for your support, guys :)
To catch what has changed between json1_dict and json2_dict, you can use the following one line, making good use of "dictionary comprehension":
changed_items = {k: [json1_dict[k], json2_dict[k]] for k in json1_dict if k in json2_dict and json1_dict[k] != json2_dict[k]}
Every key of changed_items will contain two values, first of json1_dict and second of json2_dict. If the changed_items you are interested in must be the keys in diff_list, then you need instead to change a little the condition within the expression:
changed_items = {k: [json1_dict[k], json2_dict[k]] for k in json1_dict if k in json2_dict and k in diff_list and json1_dict[k] != json2_dict[k]}
all you need afterwards is to print(changed_items)
import json
# Load JSON files
with open('json_old.json') as json_file1:
json1_dict = json.load(json_file1)
with open('json_new.json') as json_file2:
json2_dict = json.load(json_file2)
diff_list = ["services", "staff", "datetime"]
# Compare the parts specified in diff_list and print the differences
result = {}
for key in diff_list:
if json1_dict['data'][key] != json2_dict['data'][key]:
result[key] = {
'old_value': json1_dict['data'][key],
'new_value': json2_dict['data'][key]
}
print(result)
# Write the differences to a result.json file
with open('result.json', 'w') as outfile:
json.dump(result, outfile)
This code snippet will compare the JSON files and print the differences in the parts specified in the diff_list variable to the console. It will also write the differences to a file named result.json.

Cypress login to REST endpoint is unauthorized, Postman works - upload of JSON file

We have a REST service with an incoming REST endpoint that accepts data. It has no web interface (Swagger or so), only the API. With Postman I can POST a JSON file (response code is 202) to it and then read the uploaded data from another endpoint.
When I want to log in to the same endpoint with Cypress to upload a JSON file from the fixtures folder (with the same body as in the Postman request), then I get response code 401 instead – Unauthorized. I have the feeling that the cypress request is wrong because the logfile of the service does not write a message when I use the cypress POST but it does when I use the Postman POST.
First question: What could I be doing wrong in the cypress request?
Second question: Once the authentication works, how can I POST/upload/push the content of the JSON file to that endpoint? Because I have no webpage to interact with, I cannot use click button functions. The documentation mainly deals with interpreting a JSON response but not with sending it.
My cypress code:
it('logs in to connector through REST API', () => {
cy.request({
method: 'POST',
url: 'localhost:8095/connector/demands/v1/demandData',
failOnStatusCode:false,
form: true,
body: {
Username: 'user',
Password: 'pass',
}
})
})
import my-request from '../fixtures/my-request.json'
it('loads the JSON file', () => {
cy.fixture('my-request.json')
})
The structure of the JSON file to upload is not too simple, here is a shortened version:
{
"#metadata": {
"context": "{{A}}"
},
"pool": "{{B}}",
"action": "NEW",
"Type": "ANNOUNCEMENT",
"ON": "Order123",
"PON": "PO123",
"SNN": "SN123",
"direction": "OUT",
"mode": 3,
"pack": [
{
"out": {
"outKey": "OUT14",
"outQuantity": "3",
"dimension": {
"length": "303",
"width": "33",
"height": "903",
"unit": "mm"
},
"layers": "3",
"weight": "3000",
"weightUnit": "grm",
"in": [
{
"inKey": "IN12",
"inQuantity": "3",
"article": {
"articleKey": "article3",
"quantity": "300",
"PON": "Art_PO300",
"SNN": "Art_SN300"
}
}
]
},
"p1": "pack3",
"p2": "pack4",
"store": true
},
{
"out": {
"outKey": "OUT23",
"outQuantity": "5",
"dimension": {
"length": "505",
"width": "55",
"height": "905",
"unit": "mm"
},
"layers": "5",
"weight": "5000",
"weightUnit": "grm",
"in": [
{
"inKey": "IN19",
"inQuantity": "5",
"article": {
"articleKey": "article5",
"quantity": "500",
"PON": "Art_PO500",
"SNN": "Art_SN500"
}
}
]
},
"p1": "pack5",
"p2": "pack5",
"store": true
}
]
}
Solution found. "form: true" must not be given because this overrides the content-type.
You can pass the contents of the fixture file(which is json) in the request body like this:
describe('Some Test Suite', function() {
// we can use these values to log in
const username = 'jane.lane'
const password = 'password123'
it('logs in to connector through REST API', () => {
cy.fixture('my-request.json').then(myFixture => {
cy.request({
method: 'POST',
url: 'localhost:8095/connector/demands/v1/demandData',
auth: {
username,
password,
},
failOnStatusCode: false,
form: true,
body: myFixture
})
})
})
})
For HTTP auth you have to use. You can check out this cypress recipe.
auth: {
username,
password,
}

Google Custom Search JSON API

I'm playing with Google Custom Search API with Custom Search Engine (CSE) via JSON API. I successfully obtained search result, but I'm clueless about how to obtain the nextPageToken.
https://www.googleapis.com/customsearch/v1?key=MY_API_KEY&cx=MY_SEARCH_ENGINE_ID&q=Testing
The JSON response is as follow:
{
"kind": "customsearch#search",
"url": {
"type": "application/json",
"template": "https://www.googleapis.com/customsearch/v1?q={searchTerms}&num={count?}&start={startIndex?}&lr={language?}&safe={safe?}&cx={cx?}&cref={cref?}&sort={sort?}&filter={filter?}&gl={gl?}&cr={cr?}&googlehost={googleHost?}&c2coff={disableCnTwTranslation?}&hq={hq?}&hl={hl?}&siteSearch={siteSearch?}&siteSearchFilter={siteSearchFilter?}&exactTerms={exactTerms?}&excludeTerms={excludeTerms?}&linkSite={linkSite?}&orTerms={orTerms?}&relatedSite={relatedSite?}&dateRestrict={dateRestrict?}&lowRange={lowRange?}&highRange={highRange?}&searchType={searchType}&fileType={fileType?}&rights={rights?}&imgSize={imgSize?}&imgType={imgType?}&imgColorType={imgColorType?}&imgDominantColor={imgDominantColor?}&alt=json"
},
"queries": {
"nextPage": [
{
"title": "Google Custom Search - Testing",
"totalResults": "2900",
"searchTerms": "Testing",
"count": 10,
"startIndex": 11,
"inputEncoding": "utf8",
"outputEncoding": "utf8",
"safe": "off",
"cx": "MY_SEARCH_ENGINE_ID"
}
],
"request": [
{
"title": "Google Custom Search - Testing",
"totalResults": "2900",
"searchTerms": "Testing",
"count": 10,
"startIndex": 1,
"inputEncoding": "utf8",
"outputEncoding": "utf8",
"safe": "off",
"cx": "MY_SEARCH_ENGINE_ID"
}
]
},
"context": {
"title": "Test Search Engine"
},
"searchInformation": {
"searchTime": 0.299265,
"formattedSearchTime": "0.30",
"totalResults": "2900",
"formattedTotalResults": "2,900"
},
"items": [
// ... Search Result here
]
}
But how to obtain result of next page via nextPageToken ?
Instead of using nextPageToken, there are 2 parameters I can add into the query string to change the page of results:
start: the start index of the result, valid values are integers > 0.
num: number of results per page, valid values are 1 ~ 10 (max 10 records can be obtained in 1 page)
Therefore to change to page 2, I have to issue:
start=11&num=10
in query string (given that record per page is 10).
Hope this helps.

Gatling: JsonPath extract multiple values

I'm building a gatling 2.1.3 scenario and I need to extract data from a json body.
Example of the body:
[
{
"objectId": "FirstFoo",
"pvrId": "413"
"type": "foo",
"name": "the first name",
"fooabilities": {
"foo1": true,
"foo2": true
},
"versions": [23, 23, 23, 23, 23, 23, 24, 23, 23],
"logo": [
{
"type": "firstlogo",
"width": 780,
"height": 490,
"url": "firstlogos/HD/{resolution}.png"
}
]
},
{
"objectId": "SecondFoo",
"pvrId": "414"
"type": "foo",
"name": "the second name",
"fooabilities": {
"foo1": true,
"foo2": false
},
"versions": [23, 23, 23, 23, 23, 23, 24, 23, 23],
"logo": [
{
"type": "secondlogo",
"width": 780,
"height": 490,
"url": "secondlogos/HD/{resolution}.png"
}
]
}
]
and I have this code trying to extract de data:
exec(
http("get object")
.get(commons.base_url_ws + "/my-resource/2.0/object/")
.headers(commons.headers_ws_session).asJSON
.check(jsonPath("$..*").findAll.saveAs("MY_RESULT"))) (1)
.exec(session => {
foreach("${MY_RESULT}", "result") { (2)
exec(session => {
val result= session("result").as[Map[String, Any]]
val objectId = result("objectId")
val version = result("version")
session.set("MY_RESULT_INFO", session("MY_RESULT_INFO").as[List[(String,Int)]] :+ Tuple2(objectId, version))
})
}
session
})
My goal is:
To extract the objectId and the 9th value from the version array.
I want it to look as Vector -> [(id1, version1),(id2, version2)] in the session to reuse later in another call to the API.
My concerns are:
(1) Is this going to create entries in the session with the complete sub objects? Because in other answers I was that is was always a map that was saved ("id" = [{...}]) and here I do not have ids.
(2) In the logs, I see that the session is loaded with a lot of data, but this foreach is never called. What could cause this ?
My experience in Scala is of a beginner - there may be issues I did not see.
I have looked into this issue: Gatling - Looping through JSON array and it is not exactly answering my case.
I found a way to do it with a regex.
.check(regex("""(?:"objectId"|"version"):"(.*?)",.*?(?:"objectId"|"version"):\[(?:.*?,){9}([0-9]*?),.*?\]""").ofType[(String, String)].findAll saveAs ("OBJECTS")))
I can then use this
foreach("${OBJECTS}", "object") {
exec(
http("Next API call")
.get(commons.base_url_ws + "/my-resource/2.0/foo/${object._1}/${object._2}")
[...]
}