Wie formatiert man einen Json Schlüsselpfad für eine API?

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
Kattamaran
User
Beiträge: 5
Registriert: Sonntag 7. November 2021, 08:09

Hallo allerseits
Bin seit kurzem lernender Python Anfängerprogrammierer. Ich versuche via einer Webshop API Produkte automatisch zu aktualisieren. Bis jetzt konnte ich mich durchgooglen. Jetzt stehe ich total auf dem Schlauch und bnötige Hilfe.
Via requests versuche ich ein Key-Value Pair zu updaten, welches nur über den Index einer Array aktualisiert werden kann. Leider gelingt es mir nicht, dies richtig zu formatieren.

Hier erstmals mein Code, welcher funktioniert, um einen Json Key zu updaten, welcher nicht in einem Array steckt:
import requests
import json
storeId = 'XXX'
productId = 'XXX'

data = {
"price": 1500
}

url = f"https://app.XXX.com/api/v3/{storeId}/pr ... {productId}"
querystring = {"token":"XXX"}
headers = {"Accept": "application/json"}

response = requests.request("PUT", url, headers=headers, params=querystring, data=json.dumps(data))
print(response.text)
Es geht um das "data" Paket. Wie kann ich in diesem den nested Pfad einbinden? Folgendes habe ich versucht:
data = {
"options/[0]/[0]/priceModifier": 30
}
Klar könnte ich einfach den kompletten Schlüsselwert von "options" senden. Jedoch ist die Information nicht konsistent. Sprich einmal befindet sich der Schlüssel priceModifier im Index 1 oder 2. Deshalb muss ich zuerst nach einer Schlüsselinformation suchen und herausfinden in welchem Index er steckt. Jedoch weiss ich eben nicht, wie ich einen eine Array mittels Indexnummer aktualisieren kann.
Hier noch ein Beispiel wie die Daten aufgebaut sind (priceModifier gibt es in diesem Beispiel vier mal):
Ich versuche hier "priceModifier":60 zu aktualisieren.
"options": [
{
"choices": [
{
"priceModifier": 60,
"priceModifierType": "ABSOLUTE",
"text": "SERVIwicklung",
"textTranslated": {
"de_CH": "SERbwicklung",
"en": "SEng"
}
},
{
"priceModifier": 0,
"priceModifierType": "ABSOLUTE",
"text": "INTERN.com",
"textTranslated": {
"de_CH": "INTERcom",
"en": "INTERcom"
}
}
],
"defaultChoice": 1,
"name": "W\u00e4hngspaket:",
"nameTranslated": {
"de_CH": "W\u00e4hlspaket:",
"en": "Pleakage:"
},
"required": true,
"type": "RADIO"
},
{
"choices": [
{
"priceModifier": 0,
"priceModifierType": "ABSOLUTE",
"text": "2 Jahre Garantie",
"textTranslated": {
"de_CH": "2 Jahre Garantie",
"en": "2 year guarantee"
}
},
{
"priceModifier": 39.9,
"priceModifierType": "ABSOLUTE",
"text": "5 Jahre Garau00e4t",
"textTranslated": {
"de_CH": "5 Jaheuger\u00e4t",
"en": "5 year guvice"
}
}
],
"defaultChoice": 1,
"name": "W\u00e",
"nameTranslated": {
"de_CH": "W\u0",
"en": "Please"
},
"required": true,
"type": "RADIO"
}
],
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

Nach welchen Regeln soll denn der "richtige" priceModifier gefunden werden?
Nach diesen Regeln mußt Du Deine Struktur durchsuchen und dabei den Index zählen.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kattamaran: Das kann man nicht sagen ohne die API zu kennen. Gibt es da denn überhaupt solche ”Pfade”? Wo/Wie sind die definiert? JSONPath ist das ja beispielsweise nicht wenn da "/" als Trenner drin vorkommen.

Nebenfrage: Warum benutzt Du das `json`-Modul und `data`-Argument von `requests` statt das Wörterbuch als `json`-Argument zu übergeben?

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
Kattamaran
User
Beiträge: 5
Registriert: Sonntag 7. November 2021, 08:09

Das ist richtig, ich muss die Indexzahlen zählen. Die "/" Trenner funktionieren nicht. Ich weiss eben nicht, wie ich einen Pfad zum Schlüssel formatieren muss, damit es funktioniert.
Ich weiss leider nicht, was du mit Argument via Wörterbuch übergeben meinst.
Ist es denn mit requests nicht möglich, ein json mit Indexnummer zu senden?
Erfolglos war auch: "options[0].choices[0].priceModifier": 33
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wir wissen auch nicht, wie der Pfad zum Schluessel formatiert werden muss. Das hat nichts mit requests oder Python zu tun, sondern damit, was die konkrete Webschnittstelle anbietet. Die wir nicht kennen, denn die Webseite hast du ja rausredigiert.
Kattamaran
User
Beiträge: 5
Registriert: Sonntag 7. November 2021, 08:09

Gibt es denn bei json keine gängige Formatierung? Wenn einen GET request abrufe, kann ich mir den primModifier auslesen mit folgendem Pfad:
print(response_json['options'][0]['choices'][0]['priceModifier'])

Also bin ich davon ausgegangen, dass via dem selben Pfad auch zurückgeschrieben werden kann. Wenn ich keine Indexnummer hätte, könnte ich ja Schlüssel adressieren.
Sorry ich programmiere seit 2 Wochen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hat __blackjack__ doch schon geschrieben. Es gibt JSON-Path. Aber OB die das benutzen oder nicht, kann hier keiner wissen. Das wird dir gerade aber auch zum 3ten mal nahegelegt 🤷‍♂️
Kattamaran
User
Beiträge: 5
Registriert: Sonntag 7. November 2021, 08:09

Und wie würde ich das mit json-path machen?
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

Was Du wie machen kannst, gibt die Webshop-API vor. Da gibt es keine allgemeingültigen Regeln.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kattamaran: Das was Du da zum Auslesen verwendest, ist kein Pfad, sondern ganz normale Python-Syntax um auf Elemente von Wörterbüchern und Listen zuzugreifen. Das ist Python in einem Python-Programm. Das hat nicht wirklich etwas mit der API der Webseite zu tun, ausser das die JSON liefert was so strukturiert ist.

Du kannst auf die selbe Art den Wert in Python nicht nur abfragen, sondern auch setzen. In Python, in der Python-Datenstruktur. Ob die geänderte Datenstruktur dann mit einem PUT wieder an den Webserver zurück muss, ist wie gesagt keine allgemeine Python- und/oder JSON-Frage, sondern hängt von der API ab die der Webserver anbietet. Versuchen könntest Du es ja mal. Wie kommst Du denn überhaupt auf die Idee das die API da irgendwie eine Art Pfad haben will?

Mit Argument als Wörterbuch übergeben meine ich das die `requests`-Funktionen neben dem `data`-Argument auch `json`-Argument haben, bei dem man das Wörterbuch nicht selbst in eine Zeichenkette mit JSON-Quelltext umwandeln muss. Das macht `requests` dann schon, und setzt auch den entsprechenden Content-Header, was Du nicht machst. Wahrscheinlich wird der falsche Header dann einfach von der Web-API ignoriert, wenn das trotzdem funktioniert. Würde ich mich aber eher nicht drauf verlassen.

Edit: Ich sehe gerade das Du den Header selbst manuell setzt. Das fällt dann auch weg.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
Kattamaran
User
Beiträge: 5
Registriert: Sonntag 7. November 2021, 08:09

Also ich kann mit dem Code ganz oben einen Top Level Schlüssel updaten. Die data ist ja im funktionierenden Code "price". Damit kann ich den Produktepreis ändern. Ich erhalte von der API eine Response 200 und dass 1 Objekt erfolgreich updated wurde.

Ich weiss einfach nicht, wie ich den Nested Schlüssel "priceModifier" der zur Zeit den Wert 60 hat, ändern kann.
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

Und zum siebten Mal: das weiß hier auch niemand, weil niemand die WebAPI kennt, die Du da benutzt und wie und ob das unterstützt wird. Dazu muß Du die Dokumentation der API lesen.
Antworten