Mit der API SDK-Integration in Flyo können OpenApi-Dateien für ausgewählte Inhalte aus Flyo erstellt werden. Die OpenApi-Datei kann mittels Generator in ein SDK umgewandelt werden, welches der gewünschten Programmiersprache entspricht. Die OpenAPI-Datei beschreibt die Endpunkte und kann auch als Dokumentation verwendet werden, um die Endpunkte zu verwenden, ohne ein SDK zu generieren.
TIP
Alle Endpunkte werden automatisch für CORS- Anfragen freigegeben.
Öffentliche Schnittstelle
Wenn ein SDK als öffentlich konfiguriert wird, wird für das Abrufen der Inhalte kein Authorization-Token verlangt. Zusätzlich werden die Endpunkte dank unserer Caching-Technologie um ein Vielfaches schneller. Es lohnt sich also, die Schnittstelle öffentlich zu machen, solange keine sensiblen Daten übertragen werden oder es eine Anforderung ist, dass der Authorization-Token ausgetauscht werden kann.
Recaptcha Verifizierung\
Wenn POST- und PUT-Requests auf einer öffentlichen Schnittstelle durchgeführt werden, müssen die Anfragen mittels Recaptcha verifiziert werden.\
Verifizieren von POST und PUT Requests
In einer SPA-Umgebung (JavaScript-Seite, die direkte Aufrufe an die API-Schnittstelle macht) ist es für ein öffentliches SDK zwingend, die Anfragen zu verifizieren. In einer SPA-Umgebung empfiehlt es sich, dies auch für nicht öffentliche SDKs einzuführen.
TIP
In einer SPA-Umgebung empfiehlt es sich immer, alle POST- und PUT-Request mittels Recaptcha zu validieren, das verhindert unnötige SPAM-Einträge und generiert somit weniger Anfragen.
Für die Verifizierung verwenden wir Google's Recaptcha V3 Mechanismus. Das heisst, dass die SPA-Webseite beim Übermitteln von POST- und PUT-Requests einen Response Code lösen muss, um zu verifizieren, dass es sich um einen wirklichen Benutzer handelt. Dieser Response Code muss mittels recaptcha_response Bestandteil der Body Parameter sein. Flyo validiert diese Response serverseitig mit dem in Flyo definierten Secret. Bei einem Fehler wird ein Validation Error ausgegeben und der Request schlägt fehl. Recpatcha JavaScript Framework Libraries: NuxtJS Recaptcha
Neue Inhalte erstellen (POST)
Inhalte, die über die API SDK-Integration in Flyo neu erstellt werden, werden nicht automatisch online geschaltet. Damit wird sichergestellt, dass Inhalte zuerst einer Prüfung unterzogen werden können, bevor sie z.B. auf einer Website erscheinen.
Bestehende Inhalte aktualisieren (PUT)
Werden bestehende Inhalte via API SDK-Integration aktualisiert, wird in der Flyo Oberfläche ein Änderungsvorschlag generiert. Inhalte werden erst aktualisiert, wenn der Änderungsvorschlag angenommen wird. Ein Änderungsvorschlag überschreibt einen vorangegangenen Änderungsvorschlag. Ein Beispiel: Wird der Titel eines Inhalts auf Test 123 geändert und später auf ABC 456, so wird in Flyo nur der neueste Änderungsvorschlag, also ABC 456 angezeigt.
Filter-Parameter
Der ?filter
-Parameter erlaubt dir, direkt auf der Schnittstelle Where-Konditionen zu setzen. Das ermöglicht es dir, nur die gewünschten Daten aufzurufen. Der ?filter
-Parameter muss dabei als Array übergeben werden.
Zur besseren Verständlichkeit kannst du dir einige Erklärungen und Beispiele anschauen.
In der OpenAPI-Datei ist der Filter wie folgt beschrieben:
Filtering\
Allows you to pass filtering options any attribute. ?filter[id]=123
or ?filter[author][like]=John
. Example of accessing nested array values: ?filter[tags.alias]=food
\
Es können mehrere Filter als UND-Verbindungen zusammengefügt werden. Als Beispiel würde ?filter[email][like]=example.com&filter[is_active]=1
alle Daten zurück geben, bei welchen die E-Mail Adresse example.com beinhaltet und is_active auf 1 ist.
Zur Filterung von Daten kannst du folgende Operatoren verwenden:
Operator | SQL | Ausdruck | Beispiel |
---|---|---|---|
eq | = | equal | ?filter[email][eq]=john@example.com |
neq | != | not equal | ?filter[email]=john@example.com |
gt | > | greater then | ?filter[created_at]=12345678 |
gte | >= | greater and equal then | ?filter[created_at]=12345678 |
lt | < | lower then | ?filter[age]=18 |
lte | <= | lower and equal then | ?filter[age]=18 |
like | LIKE '%xyz%' | contains | ?filter[content]=Foobarsdk |
in | IN (X,Z) | contained in an array (OR connection) | ?filter[id][]=X&filter[id][]=Y |
nin | NOT IN (X,Z) | not contained in an array (OR connection) | ?filter[id][]=X&filter[id][]=Y |
TIP
Wenn ein boolescher Wert verlangt wird, werden true
und false
über die Abfrageparameter als Zeichenkette interpretiert. Aus diesem Grund wird Flyo true
, True
oder auch TRUE
als booleschen Wert zu true
konvertieren und
Verschachtelte Objekte / Arrays
Ein wichtiges Element bei der Abfrage von Daten ist der Zugriff auf verschachtelte Elemente, also auf verschachtelte Objekte oder Arrays. Eine Beispielantwort mit einem Array von Tags und einem Objekt namens "state" sieht wie folgt aus:
[
{
"id": 1,
"title": "Flyo Cloud",
"state": {
"online": 1
},
"tags": [
{
"id": 1,
"alias": "essen"
},
{
"id": 2,
"alias": "bar"
}
]
}
]
Arrays
Es ist möglich, alle Einträge zu filtern, die ein bestimmtes verschachteltes Element enthalten. Um auf ein verschachteltes Element zuzugreifen, wird ein Punkt (.
) verwendet, z.B. tags.alias
. Ein vollständiges Beispiel für den Aufruf eines verschachtelten Array-Elements wäre ?filter[tags.alias]=essen
. Wenn mehrere verschachtelte Verbindungen angewendet werden, werden diese als ODER-Verbindung eingesetzt, z.B. ?filter[tags.alias]=essen&filter[tags.alias]=trinken
- alle Einträge mit dem Tag "essen" ODER "trinken".
Objekte
Um mit dem obigen Beispiel alle Einträge abzurufen, bei denen state.online = 1
, wird ein Doppelpunkt (:
) verwendet. Dadurch kann direkt auf das Element eines Objekts verwiesen werden. Ein Beispielaufruf, um alle Einträge mit dem Zustand 1 abzurufen, würde wie folgt aussehen: ?filter[state:online]=1
. Es sind auch alle Operatoren aus der Liste möglich, z.B. ?filter[state:online]=1
.
AND/OR Verbindungen
Innerhalb der Filterung können AND
und OR
-Verknüpfungen vorgenommen werden. Dies erhöht jedoch die Komplexität der Parameterspezifikation erheblich. Am einfachsten lässt sich dieser Filter daher in einer Array-Annotation darstellen, hier als Beispiel in JavaScript ein Filter, der alle Einträge mit Bahnhofstraße und einem dieser ausgewählten Tags ausgibt:
{
"and": [
{
"content": {
"like": "Foobar"
}
},
{
"or": [
{
"tags.alias": "tag1"
},
{
"tags.alias": "tag2"
}
]
}
]
}
Die Annotation des filter
Parameters würde wie folgt aussehen:
filter[and][0][content][like]=Foobar&filter[and][1][or][0][tags.alias]=tag1&filter[and][1][or][1][tags.alias]=tag2
Diese Ausgabe wurde mit 3v4l.org erstellt. Dieser Online PHP Shell kann dich beim Erstellen von Filterabfragen unterstützen.
Beispiele
Hier ein paar Beispiele zur Veranschaulichung und Kombination der Filter:
?filter[tags.id][]=X&filter[tags.id][]=Y\
Einträge mit dem Tag ID X oder Y. In einem SQL-Format würde dies wie folgt aussehen: WHERE tags.id IN (X,Y)
\
?filter[id][in][]=X&filter[id][in][]=Y
Einträge mit der ID X oder Y. In einem SQL-Format würde dies wie folgt aussehen: WHERE id IN (X,Y)
?filter[id][in][]=X&filter[id][in][]=Y&filter[start_timestamp][lt]=1654466400
Einträge, die kleiner sind als 1654466400 und Tags X oder Y haben. In einem SQL-Format würde dies wie folgt aussehen: WHERE start_timestamp <= 1654466400 AND id IN (X,Y)
?filter[or][0][firstname]=Foo&filter[or][1][lastname]=Bar
Eine einfach ORDER Verbindung anstelle von UND Verbindung als SQL WHERE firstname = 'Foo' OR lastname = 'Bar'
veranschaulicht mittels PHP:
['or' => [['firstname' => 'Foo'], ['lastname' => 'Bar']]];
?filter[and][0][content][like]=Foobar&filter[and][1][or][0][tags.alias]=tag1&filter[and][1][or][1][tags.alias]=tag2
Ein Beispiel mit UND und ODER Verbindungen als SQL WHERE (content LIKE
%Foobar%) AND (tags.alias = 'tag1' OR tags.alias = 'tag')
veranschaulicht mittels PHP:
[
'and' => [
[
'content' => ['like' => 'Foobar'],
],
[
'or' => [
['tags.alias' => 'tag1'],
['tags.alias' => 'tag2'],
],
],
],
]
In einem JavaScript SDK Kontext könnte der Filter-Paramter wie folgt verwendet werden sdk.getXYZPool({filter: [{'tags.alias':'essen'}]})
oder in PHP SDKs $apiInstance->getPointsOfInterestPool(1, 100, '-id', ['tags.alias' => 'essen'])
. In einer PHP Umgebung können die Filter wie folgt als query param übergeben werden urldecode(http_build_query(['filter' => [/*...*/]))
.
OpenAPI Generator Serializer Problem mit JavaScript/TypeScript
Der OpenAPI Generator hat Probleme mit der Serialisierung verschachtelter Objekte. Um einen Filter in JavaScript oder TypeScript korrekt zu implementieren, muss die queryParamsStringify
-Funktion angepasst werden:
Installiere qs mittels
npm install qs
.Importiere die
stringify
-Funktion:import { stringify } from 'qs'
.Überschreibe die
queryParamsStringify
-Funktion in der SDK-Konfiguration:javascriptconst config = new Configuration({ queryParamsStringify: (queryParams) => stringify(queryParams) });
Beispiel (mit verwendung der neuen config-Variable):
javascriptconst api = new BlogsApi(config); api.getBlogsPool({ filter: { 'tags.unique_id': { 'in': ['12345', '67890'] } } });
Felder limitieren
Standardmässig werden alle Felder zurückgegeben, die in Flyo für den Content Pool ausgewählt wurden. Um nur bestimmte Felder aus dieser Auswahl zurückzugeben und damit den Datentransfer schlank zu halten, kann mit dem Abfrageparameter fields
eine komma-separierte Liste von Feldern angegeben werden, die zurückgegeben werden sollen, z.B. fields=id,firstname,lastname
.
Felder sortieren
Um die Ausgabe zu sortieren, kann der Parameter sort
verwendet werden, wobei ASC
einem vorangestellten +
oder keinem Vorzeichen und DESC
einem -
entspricht. Mehrere Sortierattribute können durch Komma getrennt angegeben werden, z.B. sort=firstname,-birthday
, was auch sort=+firstname,-birthday
entspricht.
ASC
= Von kleinen zu grossen Zeichen/Zahlen 1,2,3 & A-Z
DESC
= Von grossen zu kleinen Zeichen/Zahlen 3,2,1 & Z-A
Paginierung
Die Rückgabedaten des SDK werden paginiert, d.h. jeweils nur eine gewisse Anzahl von Einträgen sind in einer einzelnen Anfrage enthalten. Alle Informationen zur Paginierung finden sich im Response-HEADER, unter folgenden Variabeln:
X-Pagination-Total-Count
Anzahl der einträge/items
X-Pagination-Page-Count
Anzahl Seiten
X-Pagination-Current-Page
Die nummer der aktuellen Seite
X-Pagination-Per-Page
Wieviel Einträge pro Seite zurück gegeben werden
Mittels per-page
(Standard ist 20 Einträge) kann man bis zu 100 Einträge pro Abrufe erhalten. Mit dem page
Parameter (default 1) kann man zur nächsten Seiten mit Einträgen wechseln.
OpenAPI Client generieren
In unserem Beispiel verwenden wir den OpenAPI Generator. Dieser muss mittels npm install @openapitools/openapi-generator-cli -g
global verfügbar sein. Es gibt aber auch andere Wege, um den Client zu generieren, siehe Installations Anleitung
Die Clients werden anhand des von Flyo für diese Integration generierten OpenApi JSON Dokument generiert. Dieses ist in der Flyo-Oberfläche sichtbar. Die URL zur JSON-Datei ist auch im Preview des SDKs zu finden.
PHP
Ein Beispiel-Command, um einen SDK-Client für PHP zu erstellen, könnte wie folgt aussehen:
openapi-generator-cli generate -i https://api.flyo.cloud/integration/sdk/<id>/<token> -g php -o sdk
Wenn das SDK in einer Applikation verwendet wird, ist es wichtig, den Composer PSR4 Eintrag in das Projekt einzufügen, das obige Beispiel würde benötigen:
"autoload" : {
"psr-4" : {
"OpenAPI\\Client\\" : "sdk/lib/"
}
}
JavaScript
Ein Beispiel-Command, um einen SDK-Client für JavaScript zu erstellen, könnte wie folgt aussehen:
openapi-generator-cli generate -i https://api.flyo.cloud/integration/sdk/<id>/<token> -g javascript -o sdk --additional-properties=usePromises=true
Um zusätzlich Docs und Tests zu deaktivieren:
openapi-generator-cli generate -i https://api.flyo.cloud/integration/sdk/<id>/<token> -g javascript -o sdk --global-property=apis,models,apiTests=false,modelsTest=false,apiDocs=false,modelDocs=false,supportingFiles --additional-properties=usePromises=true
Füge nicht benötigte Dateien zu .gitignore
hinzu, hier ein Beispiel:
sdk/.*
sdk/test
sdk/git*
sdk/mocha*
sdk/package*
NuxtJSPlugin
Wenn das populäre NuxtJS Framework verwendet wird, empfiehlt es sich, ein Plugin zu erstellen:
export default ({ app }, inject) => {
const WebsiteSDK = require('~/sdk/src/index.js');
const defaultClient = WebsiteSDK.ApiClient.instance;
// reset or set oder headers in config of the client
defaultClient.defaultHeaders = {}
const bearerAuth = defaultClient.authentications['bearerAuth'];
bearerAuth.accessToken = "__INSERT_TOKEN__"
inject('sdk', WebsiteSDK)
inject('pois', new WebsiteSDK.PoisApi())
}