Beispiele rest json
Inhaltsverzeichnis
Daten von einem REST-Server holen, anzeigen und bearbeiten
Der REST-Server
Unter https://api.predic8.de/shop/products/ ist ein REST-Server zu finden, der als Beispiel-Server der Allgemeinheit zur Verfügung steht. Der Aufruf der URL gibt die folgenden Daten zurück:
{ "meta": { "count": 32, "limit": 10, "page": 1, "next_url": "/shop/products/?page=2&limit=10" }, "products": [ { "name": "Bananas", "product_url": "/shop/products/3" }, { "name": "Oranges", "product_url": "/shop/products/10" }, ... { "name": "Apple", "product_url": "/shop/products/18" }, { "name": "Green Grapes", "product_url": "/shop/products/11" } ] }
Daten von mehreren Seiten zusammenfassen
Die Daten sind auf mehrere Seiten aufgeteilt. Für unsere Zwecke müssen wir sie zusammenfassen. Dazu eignet sich die Prozedur #http_loop_json.
In solchen Fällen hat es sich bewährt, das erst mal als Konsolen-Anwendung zu realisieren, und das dann in die konkrete Anwendung zu kopieren. Diese Konsolen-Anwendung würde wie folgt aussehen:
#frm c="c_test_json" y=console #code url=https://api.predic8.de/shop/products/ #code nurl="https://api.predic8.de$JSON_VALUE(1,meta.next_url)" #code ready=$EMPTY($JSON_VALUE(1,meta.next_url)) #http_loop_json y=get se=N $CODE$ isc=Y m=20 #coutl $JSON_TEXT(1,frm) #cout c="c_test_json executed"
Die Prozedur #http_loop_json verwendet y=get als Method, wir wollen schließlich Daten abfragen. Als url verwenden wir die Seite https://api.predic8.de/shop/products/.
Sobald die erste Seite da ist, wird die nächste Seite aufgerufen, und deren URL wird mit nurl ("next URL") angegeben. Dazu wird aus dem Anwort-JSON das Feld meta-next_url extrahiert ($JSON_VALUE(1,meta.next_url), #http_loop_json arbeitet auf dem ersten JSON), davor wird der Rest der erforderlichen URL ergänzt. Daneben benötigt #http_loop_json auch noch einen Hinweis, wann die Schleife beendet werden soll, das ist dann der Fall, wenn meta.next_url leer ist. Sicherheitshalber setzt man bei #http_loop_json noch m=20, nach spätestens 20 Seiten wird also auch abgebrochen.
Da der Server ein abgelaufenes Zertifikat hat, setzen wir isc=Y. Anschließend wird mit #coutl $JSON_TEXT(1,frm) das Ergebnis formatiert ausgegeben:
{ "products": [ { "name": "Bananas", "product_url": "/shop/products/3" }, { "name": "Oranges", "product_url": "/shop/products/10" }, { "name": "Pineapples", "product_url": "/shop/products/33" }, ... { "name": "Pistachio", "product_url": "/shop/products/76" } ], "meta": { "count": 32, "limit": 10, "page": 4, "previous_url": "/shop/products/?page=3&limit=10" } }
Die Prozedur #http_loop_json fügt bei Arrays auf der obersten Ebene (hier products) weitere Array-Elemente hinzu (die Anzeige eben wurde an der Stelle ... gekürzt, die Liste wäre sonst deutlich länger), während Objekte überschrieben werden (hier meta).
ID extrahieren
Wir können später die ID gebrauchen, von daher wollen wir diese auch extrahieren.
#http_loop_json y=get se=N $CODE$ isc=Y m=20 #cmd_clear #json_chgdata n=json path=id add=Y is=N z="$STREXTR($JSON_DATA(json,product_url),ffe,/shop/products/)" #json_loop n=json er=1 path=products #coutl $JSON_TEXT(1,frm)
Vor der Ausgabe fügen wir eine #json_loop ein, die durch das Array products geht und für jeden Eintrag die zuvor definierte lokale Prozedur aufruft. Hier wird mit #json_chgdata das jeweilige Element in der Loop geändert, genau genommen - da add=Y - wird ein neues Element namens path=id dem jeweiligen Array-Element hinzu. Der Wert von id wird mit dem Parameter z bestimmt. Hier holen wir die product_url aus dem JSON und extrahieren alles, was nach /shop/products/ kommt.
Die Ergebnismenge (Ausschnitt) sieht nun wie folgt aus:
{ "products": [ { "name": "Bananas", "product_url": "/shop/products/3", "id": 3 }, { "name": "Oranges", "product_url": "/shop/products/10", "id": 10 }, ...
Einen Tree füllen
Nun wollen wir mit den Daten in eine konventionelle Oberfläche und legen mit dem Wizard das Kommando xtestrest an. Für das Sub-Kommando xtestrest_flt verwenden wir
#tree_clear #tree_add u=root c=Produkte si=Y s="#page_fill d=xtestrest_page_produkte" o=xtestrest_open(produkte)
Die Produkte laden wir dann in xtestrest_open.
~ $ICP(0,produkte) #code url=https://api.predic8.de/shop/products/ #code nurl="https://api.predic8.de$JSON_VALUE(1,meta.next_url)" #code ready=$EMPTY($JSON_VALUE(1,meta.next_url)) #http_loop_json y=get se=N $CODE$ isc=Y m=20 #cmd_clear #json_chgdata n=json path=id add=Y is=N z="$STREXTR($JSON_DATA(json,product_url),ffe,/shop/products/)" #json_loop n=json er=1 path=products #tree_fill u=o q=json path=products c1=id c2=name s="#page_fill d=xtestrest_page_produkt rs=Y" ~~
Bis auf #tree_fill ist das vom eben erstellten Konsolen-Kommando 1:1 kopiert. Als Datenquelle geben wir q=json ein, also werden die Daten aus dem ersten JSON geholt. Mit ID und name werden die entsprechenden Werte aus dem JSON geholt.
Ein VL-Segment füllen
Wenn wir https://api.predic8.de/shop/products/3 aufrufen, dann erhalten wir die Details zum Produkt zurück.
{ "name": "Bananas", "price": 0.99, "photo_url": "/shop/products/3/photo", "category_url": "/shop/categories/Fruits", "vendor_url": "/shop/vendors/672" }
Diese wollen wir nun in einem VL-Segment anzeigen. Das sieht erst mal wie folgt aus:
#grid #prim as=Y #cat as=Y c="Daten aus https://api.predic8.de/shop/products/" #vl_seg cc=5 w1=70 w2=50 w3=20 w4=70 w5=200 n=vl #vl_line c1=ID c2=$FND(s,id) nd2=Y nvi2=neu c3=" " c4=Name f5=name #vl_line c1=Preis f2=price y2=curr a2=d2 c3=" " c4=Kategorie f5=category_url #vl_line c1=Lieferant c3=" " c4=Name f5=vendor_url #http_request y=get se=N response=resp isc=Y url=https://api.predic8.de/shop/products/$FND(s,id) #json_parse json=$VAR(resp) #vl_data q=json k=id isc=Y
Das zeigt ja immerhin schon mal die Daten an, aber ansonsten gibt es noch einiges zu tun.
Zunächst einmal haben wir bei der Kategorie und dem Lieferanten Verweise auf andere Seiten. Bei der Kategorie könnte man mit der Funktion $STREXTR() die Kategorie rausziehen, aber das würde dann zum Problem, wenn wir die Daten ändern wollen. Also machen wir es gleich richtig und legen eine Nachschlageliste an:
Nachschlagelisten
Für die Nachschlagelisten nutzen wir jetzt noch mal c_test_json und bauen eine Text-ValueList erst mal in der Konsolen-Anwendung auf. Zunächst sieht das mal ziemlich ähnlich wie eben aus, wir nutzen wieder #http_loop_json (im Moment haben wir nur eine Seite, aber es könnten ja mehr werden...), lediglich products wird durch vendors ersetzt.
#frm c="c_test_json" y=console #code url=https://api.predic8.de/shop/vendors/ #code nurl="https://api.predic8.de/shop/products/$STREXTR($JSON_VALUE(1,meta.next_url),ffe,/shop/vendors/)" #code ready=$EMPTY($JSON_VALUE(1,meta.next_url)) #http_loop_json y=get se=N $CODE$ isc=Y m=20 #json_tvl n=1 path=vendors ckey=vendor_url cvalue=name #coutl $TEXT(1) #cout c="c_test_json executed"
Mit #json_tvl wird das JSON in eine Text-ValueList übersetzt, da n=1, ist das Ergebnis dann im ersten Text. Der Pfad zum Array ist vendors, in Anlehnung der Spaltenbenennung in SQL-Nachschlagelisten heißen die Parameter für die einzelnen Felder dann ckey und cvlaue. Wir bekommen dann das folgende Ergebnis:
/shop/vendors/672=Western Tasty Fruits Ltd. /shop/vendors/32=Exotic Fruits Company /shop/vendors/501=Home Fruits /shop/vendors/810=Fun Fresh Fruits Ltd. /shop/vendors/67=Nuts for Nuts Company
Diese Nachschlageliste können wir dann in unserem VL-Segment verwenden, und für die Kategorien machen wir das entsprechend:
-- Nachschlageliste Verndors #code url=https://api.predic8.de/shop/vendors/ #code nurl="https://api.predic8.de/shop/products/$STREXTR($JSON_VALUE(1,meta.next_url),ffe,/shop/vendors/)" #code ready=$EMPTY($JSON_VALUE(1,meta.next_url)) #http_loop_json y=get se=N $CODE$ isc=Y m=20 #json_tvl n=1 path=vendors ckey=vendor_url cvalue=name -- Nachschlageliste Categories #code url=https://api.predic8.de/shop/categories/ #code nurl="https://api.predic8.de/shop/products/$STREXTR($JSON_VALUE(1,meta.next_url),ffe,/shop/categories/)" #code ready=$EMPTY($JSON_VALUE(1,meta.next_url)) #http_loop_json y=get se=N $CODE$ isc=Y m=20 #json_tvl n=2 path=categories ckey=category_url cvalue=name #vl_seg cc=5 w1=70 w2=50 w3=20 w4=70 w5=200 n=vl #vl_line c1=ID c2=$FND(s,id) nd2=Y nvi2=neu c3=" " c4=Name f5=name #vl_line c1=Preis f2=price y2=curr a2=d2 c3=" " c4=Kategorie f5=category_url y5=lookup ld5=tvl2 #vl_line c1=Lieferant c3=" " c4=Name f5=vendor_url y5=lookup ld5=tvl1
Die entsprechenden Felder werden mit y5=lookup auf Nachschlageliste umgestellt, und mit ld5=tvl1 beziehungsweise ld5=tvl2 werden die Werte aus dem ersten oder zweiten Text gezogen. Wichtig dann auch, dass bei der zweiten Prozedur #json_tvl n=2 gesetzt wird.