Jede SENAITE-Installation bringt eine JSON-API mit. Sie braucht kein Add-on und keine Konfiguration, und sie antwortet mit den Berechtigungen, die der Benutzer auch im Browser hat. Dieser Beitrag geht eine erste Sitzung durch: die Anfragen der ersten zehn Minuten, was zurückkommt, und die Fehler, durch die eine Integration nichts liefert, ohne zu sagen, warum.
Die Beispiele verwenden curl gegen eine lokale Instanz.
Ersetzen Sie Host und Zugangsdaten durch Ihre eigenen, und
verwenden Sie HTTPS für alles, was nicht auf Ihrem eigenen
Rechner läuft.
Die Basis-URL
Die API liegt unterhalb der Site, nicht unterhalb der Server-Wurzel:
http://localhost:8080/senaite/@@API/senaite/v1
senaite ist die ID der Site. Die meisten Installationen
behalten sie bei; wurde Ihre unter einem anderen Namen angelegt,
gehört dieser Name an diese Stelle. Am schnellsten prüfen Sie die
URL mit dem Versions-Endpunkt:
curl -u admin:admin \
"http://localhost:8080/senaite/@@API/senaite/v1/version"
{"url": "http://localhost:8080/senaite/@@API/senaite/v1/version",
"date": "unreleased", "version": "2.7.0", "_runtime": 8.5e-05}
Ressourcen sind Typnamen
Die erste Überraschung für die meisten Integratoren: Ressourcen
sind die internen Typnamen in Kleinbuchstaben. Eine Probe heißt
intern AnalysisRequest, ihre Ressource ist also
analysisrequest.
| Was Sie suchen | Ressource |
|---|---|
| Proben | analysisrequest |
| Analysen | analysis |
| Kunden | client |
| Kundenkontakte | contact |
| Probenarten | sampletype |
| Arbeitsblätter | worksheet |
| Batches | batch |
/samples antwortet ebenfalls, deshalb fällt der Fehler leicht
nicht auf. Es liefert genau einen Eintrag: den Ordner hinter der
Probenliste, nicht die Proben.
Eine erste Liste
curl -u admin:admin \
"http://localhost:8080/senaite/@@API/senaite/v1/analysisrequest?limit=2&fields=id,review_state"
{
"count": 52, "pagesize": 2, "page": 1, "pages": 26,
"next": "http://localhost:8080/senaite/@@API/senaite/v1/analysisrequest?fields=id%2Creview_state&limit=2&b_start=2",
"previous": null,
"items": [
{"id": "DW-0001", "review_state": "verified"},
{"id": "WW-0001", "review_state": "verified"}
]
}
count ist die Gesamtzahl der Treffer, nicht die Zahl der
Einträge in dieser Antwort. next ist eine fertige URL für die
nächste Seite. Die Einzelheiten stehen im
Beitrag zur Paginierung.
fields beschränkt jeden Eintrag auf die genannten Schlüssel.
Ohne fields trägt ein Listeneintrag rund sechzig Schlüssel: die
Metadaten, die der Probenkatalog speichert, etwa
getClientTitle, getSampleTypeTitle, getDateReceived,
getDueDate und review_state. Sie kommen direkt aus dem
Katalog, deshalb bleibt eine Liste auch bei großen Datenbanken
schnell.

Der vollständige Datensatz
Ein Listeneintrag ist eine Zusammenfassung. Alles, was eine Probe weiß, bekommen Sie über ihre UID, die 32-stellige Kennung, die jedes Objekt sein ganzes Leben lang behält:
curl -u admin:admin \
"http://localhost:8080/senaite/@@API/senaite/v1/<uid>"
Das liefert den Datensatz selbst, ohne Seitenhülle, bei einer
Probe mit rund 140 Schlüsseln. Verweise auf andere Objekte kommen
als kleine Objekte mit uid, url und api_url zurück, denen
ein Client folgen kann:
"SampleType": {
"uid": "4fc5054ebe8f416d88764809db4bcb30",
"url": "http://localhost:8080/senaite/setup/sampletypes/sampletype-1",
"api_url": "http://localhost:8080/senaite/@@API/senaite/v1/sampletype/4fc5054ebe8f416d88764809db4bcb30"
}
Mit complete=yes liefert auch eine Liste vollständige
Datensätze für jeden Eintrag. Kombinieren Sie das mit einem
kleinen limit: Jeder Eintrag lädt dann das Objekt aus der
Datenbank, statt den Katalog zu lesen.
Auf Indizes filtern
Jeder Index des Katalogs hinter einer Ressource funktioniert als Abfrageparameter. Proben, die eingegangen sind, aber noch keine übermittelten Ergebnisse haben:
".../analysisrequest?review_state=sample_received"
Wiederholen Sie einen Parameter, um einen von mehreren Werten zu treffen:
".../analysisrequest?review_state=sample_received&review_state=to_be_verified"
Weitere nützliche Probenindizes sind getClientUID,
getClientSampleID, getSampleTypeUID, getBatchUID und die
Datumsindizes getDateReceived, getDateVerified und
getDueDate. Die verbindliche Liste liefert die API selbst:
".../catalogs/senaite_catalog_sample"
gibt die indexes des Katalogs und sein Metadaten-schema
zurück. Für Freitext durchsucht q denselben Text wie das
Suchfeld der Probenliste: Proben-ID, Kunden-Proben-ID,
Bestellnummer, Kundenreferenz, Kundenname und Kunden-ID,
Probenart, Probenahmestelle und Batch-ID.
Die Ergebnisse einer Probe
Analysen haben eine eigene Ressource und einen eigenen Katalog. Für die Ergebnisse einer Probe filtern Sie auf die Proben-ID:
".../analysis?getRequestID=DW-0001&fields=getKeyword,getResult,getUnit,review_state"
{"count": 3, "items": [
{"getKeyword": "Turb", "getResult": "0.8", "review_state": "verified"},
{"getKeyword": "pH", "getResult": "7.4", "review_state": "verified"},
{"getKeyword": "Cond", "getResult": "342", "review_state": "verified"}
]}
Ergebnisse sind Zeichenketten, und eine Analyse ohne Ergebnis hat
eine leere. Verwendet eine Analysenleistung Ergebnisoptionen, ist
der gespeicherte Wert der Wert der Option, nicht ihr Text. Ein
Ergebnis unterhalb einer Nachweisgrenze führt sein < oder >
in einem eigenen Feld, DetectionLimitOperand, im vollständigen
Datensatz. Lesen Sie beides, bevor Sie ein Ergebnis als Zahl
behandeln.
Hängen Sie workflow=1 an die Anfrage eines einzelnen
Datensatzes, enthält die Antwort workflow_info: den aktuellen
Status und die Übergänge, die der angemeldete Benutzer jetzt am
Objekt ausführen darf.
Drei stille Fehler
Diese drei stecken hinter den meisten Anfragen, bei denen die API angeblich nichts liefert.
Falsche Zugangsdaten schlagen nicht fehl. Eine Anfrage mit
falschem Passwort oder ganz ohne bekommt HTTP 200 und ein leeres
Ergebnis, weil ein anonymer Besucher eben nichts sehen darf. Ihr
Client meldet Erfolg und verarbeitet null Einträge. Ist count
dort null, wo Sie Daten erwarten, prüfen Sie zuerst die
Zugangsdaten.
Unbekannte Parameter werden ignoriert. Ein Tippfehler wie
reviewstate statt review_state erzeugt keinen Fehler. Der
Parameter fällt weg, und Sie bekommen alle Proben. Dasselbe
passiert, wenn Sie auf einen Feldnamen filtern, der kein Index
ist, etwa DateReceived statt getDateReceived. Vergleichen Sie
während der Entwicklung count mit dem, was Sie erwarten.
Die API sieht, was der Benutzer sieht. Suchen werden nach den Berechtigungen des angemeldeten Benutzers gefiltert. Ein Benutzer, der mit einem Kundenkontakt verknüpft ist, sieht die Proben dieses Kunden und sonst nichts. Für ein Kundenportal ist das richtig, für einen nächtlichen Export verwirrend. Geben Sie jeder Integration einen eigenen Laborbenutzer mit den Rollen, die sie braucht, statt ein persönliches Konto zu verwenden.
Woher die API kommt
Das Konzept ist älter als SENAITE. Bevor es SENAITE gab, schrieb
Ramon Bartl plone.jsonapi.routes, eine JSON-API für das
Content-Management-System, auf dem SENAITE aufbaut. Als SENAITE
2017 entstand, wurde senaite.jsonapi nach demselben Konzept
gebaut; laut seiner Dokumentation teilt es den größten Teil seines
Software-Designs mit plone.jsonapi.routes. Daher sind Ressourcen
Typnamen, Filter sind Katalogindizes, und die API sieht genau das,
was der Benutzer sieht.
Auf der Plone Conference 2017 in Barcelona hat Ramon das Konzept
im Browser gezeigt: Inhalte lesen, anlegen, ändern und löschen,
eine JavaScript-Anwendung, die über die API arbeitet, und wie man
die API erweitert. Der Vortrag (auf Englisch) entstand kurz nach
dem ersten Commit von senaite.jsonapi, und das meiste davon
gilt noch heute.
Loading this video will connect you to YouTube (Google LLC, USA) and transmit your IP address. By clicking play you consent to this transfer. See our privacy policy.
Wie es weitergeht
Lesen ist die sichere Hälfte der API. Proben anlegen, Ergebnisse
setzen und Übergänge ausführen läuft über dieselbe Basis-URL mit
POST-Anfragen und gehört auf ein Testsystem, bevor es
Produktionsdaten berührt. Auf der Leseseite behandelt der
Beitrag zur Paginierung,
was jede Integration als Nächstes braucht, und
der Beitrag zu den Katalogen
erklärt, warum manche Filter schnell sind und andere gar nicht
existieren.