Die REST-API hat ein paar nützliche Funktionen integriert, die für verschiedene Anwendungsgebiete genutzt werden können.
JSONP zurückliefern
JSONP steht für „JSON mit Padding“. Es erlaubt das Nachladen von Inhalten externer Domains. Normalerweise würde dies jeder Browser (Aufgrund der Same-Origin-Policy) blockieren. Mit dem _jsonp
-Parameter lässt sich das umgehen. Man muss dazu eine JavaScript-Funktion übergeben, wie folgendes Beispiel zeigt:
<script>
function receive_data( data ) {
console.log( data );
}
</script>
<script src="https://test.local/wp-json/?_jsonp=receive_data"></script>
Anfrage-Methode überschreiben
Einige Server und auch Clients können bestimmte HTTP-Methoden nicht richtig verarbeiten. Als Beispiel wäre hier die DELETE
-Anweisung genannt, die manche Clients gar nicht zur Verfügung stellen.
Um trotzdem eine DELETE
-Anweisung senden zu können, gibt es zwei verschiedene Möglichkeiten:
1) _method
-Parameter
Man hängt den Parameter _method
an die URL an oder übergibt sie mit weiteren POST-Parametern. Beispiel:
POST http://test.local/wp-json/wp/v2/posts/1?_method=delete
2) X-HTTP-Method-Override
-Header
Alternativ kann man einen zusätzlichen Header – wie oben genannt – senden:
POST /wp-json/wp/v2/posts/1 HTTP/1.1
Host: test.local
X-HTTP-Method-Override: DELETE
Alle Rücksende-Daten in die Antwort verpacken
Manche Clients können bestimmte Antworten eines Servers nicht richtig verarbeiten. Wenn beispielsweise der Statuscode oder bestimmte Header nicht zurückgegeben werden können, kann man den _envelope
-Parameter anhängen:
GET http://test.local/wp-json/wp/v2/posts/1
würde folgendes zurückgeben:
{
"id": 1,
"slug": "hallo-welt",
"status": "publish",
"type": "post",
"title": {
"rendered": "Hallo Welt!"
},
...
}
Mit dem _envelope
-Parameter sieht es wie folgt aus. Eine Anfrage an:
GET http://test.local/wp-json/wp/v2/posts/1?_envelope
ergibt:
{
"body": {
"id": 1,
"slug": "hallo-welt",
"status": "publish",
"type": "post",
"link": "http://test.local/2018/01/22/hallo-welt/",
"title": {
"rendered": "Hallo Welt!"
},
...
},
"status": 200,
"headers": {
"Link": "<http://test.local/2018/01/22/hallo-welt/>; rel=\"alternate\"; type=text/html",
"Allow": "GET"
}
}
Links
Die meisten Antworten einer Abfrage enthalten weitere Links zu anderen Ressourcen die mit dem Treffer in Relation stehen. Zum Beispiel enthält ein Abruf eines Beitrags
GET http://test.local/wp-json/wp/v2/post/1
auch die Autor-ID, die ID zu einem Beitragsbild und mehr. In der Regel wird jedoch nur die ID des Objekts, welches in der Relation steht, zurückgegeben. Über den _links
-Parameter der Antwort erhält man sofort die URL, die man nutzen kann, um weitere Abfragen zu starten. Das Beispiel von oben ergibt die Ausgabe (verkürzt):
{
"id": 1,
"title": {
"rendered": "Hallo Welt!"
},
...
"_links": {
"collection": [
{
"href": "http://test.local/wp-json/wp/v2/posts"
}
],
"author": [
{
"embeddable": true,
"href": "http://test.local/wp-json/wp/v2/users/1"
}
],
"replies": [
{
"embeddable": true,
"href": "http://test.local/wp-json/wp/v2/comments?post=1"
}
],
"version-history": [
{
"href": "http://test.local/wp-json/wp/v2/posts/1/revisions"
}
],
"wp:attachment": [
{
"href": "http://test.local/wp-json/wp/v2/media?parent=1"
}
],
"wp:term": [
{
"taxonomy": "category",
"embeddable": true,
"href": "http://test.local/wp-json/wp/v2/categories?post=1"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "http://test.local/wp-json/wp/v2/tags?post=1"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
Man unterscheidet dabei zwischen drei verschiedenen Arten von Relationen:
- Eine standardisierte Relation. Dazu gehört zum Beispiel der Autor. Eine vollständige Liste findet man hier: http://www.iana.org/assignments/link-relations/link-relations.xhtml#link-relations-1
- Eine URI-Relation. Hier würde man die gesamte URL als Schlüssel verwenden (siehe Beispiel unten). Allerdings wäre das im Code dann sehr schlecht handhabbar und unübersichtlich. Deswegen nutzt man die CURIE-Relation.
- Eine CURIE-(Compact-URI) Relation. Hier werden die Kürzel im Parameter
curies
übergeben. Damit könnte man sich die URL dann wieder selbst zusammen bauen, falls nötig. Siehe Beispiel unten.
Exkurs URI-Relationen
Beispiel URI-Relation (kommt so in WordPress nicht vor)
{
...
"_links": {
"https://api.w.org/attachment": [
{
"href": "http://test.local/wp-json/wp/v2/media?parent=1"
}
],
...
}
}
In JavaScripte müsste man das attachment
-Property in etwa so ansprechen:
data._links["https://api.w.org/attachment"]
Beispiel CURIE-Relation
Aus dem URI-Relation-Beispiel würde folgendes werden:
{
...
"_links": {
"wp:attachment": [
{
"href": "http://test.local/wp-json/wp/v2/media?parent=1"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
Man ergänzt quasi den Parameter curies
und stellt so klar, welche Relation gemeint ist. Das wp:attachment
würde dann zu https://api.w.org/attachment
werden. Der Aufruf ist allerdings deutlich kürzer. In einem JavaScript-Code könnte man den Wert wie folgt ansprechen:
data._links["wp:attachment"]
Die Link-Objekte enthalten alle einen Wert der mit href
gekennzeichnet ist. Er enthält die volle URL zum verwandten Objekt. Möchte man also den Autor erhalten, kann man einen Abruf an:
GET http://test.local/wp-json/wp/v2/users/1
senden und erhält damit alle Informationen zum Autor.
Wie man sieht, enthält der Autor noch einen weiteren Wert. Nämlich embeddable: true
. Das bedeutet, dass man sich eine Abfrage sparen könnte, wenn man den Parameter _embed
an die Ursprungs-URL anhängt. Das funktioniert wie folgt:
Anfragen einsparen
Wie gerade erwähnt, enthalten manche Antworten des Servers Links zu weiteren Inhalten. Hier beispielhaft die Antwort auf die Anfrage einer Seite:
GET http://test.local/wp-json/wp/v2/pages/2
Ergibt:
{
"id": 2,
"title": {
"rendered": "Beispiel-Seite"
},
"author": 1,
"featured_media": 0,
"parent": 0,
...
"_links": {
"self": [
{
"href": "http://test.local/wp-json/wp/v2/pages/2"
}
],
"collection": [
{
"href": "http://test.local/wp-json/wp/v2/pages"
}
],
"about": [
{
"href": "http://test.local/wp-json/wp/v2/types/page"
}
],
"author": [
{
"embeddable": true,
"href": "http://test.local/wp-json/wp/v2/users/1"
}
],
"replies": [
{
"embeddable": true,
"href": "http://test.local/wp-json/wp/v2/comments?post=2"
}
],
"version-history": [
{
"href": "http://test.local/wp-json/wp/v2/pages/2/revisions"
}
],
"wp:attachment": [
{
"href": "http://test.local/wp-json/wp/v2/media?parent=2"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
Möchte man nun an die Daten des Autors kommen, müsste man eine weitere Anfrage an den Webserver senden. Diese weitere Anfrage kann man sich einsparen, wenn man den Parameter _embed
anhängt. Dann nämlich wird die REST-API weiteren Daten gleich mit zurückliefern. Eine Anfrage wie folgt:
GET http://test.local/wp-json/wp/v2/pages/2?_embed
liefert dann folgendes:
{
"id": 2,
"title": {
"rendered": "Beispiel-Seite"
},
"author": 1,
"featured_media": 0,
"parent": 0,
...
"_embedded": {
"author": [
{
"id": 1,
"name": "florian",
"url": "",
"description": "",
"link": "http://test.local/author/florian/",
"slug": "florian",
"avatar_urls": {
"24": "http://0.gravatar.com/avatar/c2b06ae950033b392998ada50767b50e?s=24&d=mm&r=g",
"48": "http://0.gravatar.com/avatar/c2b06ae950033b392998ada50767b50e?s=48&d=mm&r=g",
"96": "http://0.gravatar.com/avatar/c2b06ae950033b392998ada50767b50e?s=96&d=mm&r=g"
},
"_links": {
"self": [
{
"href": "http://test.local/wp-json/wp/v2/users/1"
}
],
"collection": [
{
"href": "http://test.local/wp-json/wp/v2/users"
}
]
}
}
]
}
}
Paginierung
In einer WordPress-Datenbank können Unmengen von Daten gespeichert sein. REST-Abfragen können daher auch richtig große Datenmengen zurückgeben. Viel mehr als man verarbeiten möchte. Aus diesem Grund erlauben die meisten API-Abfragen, die eine Liste von Daten zurückgeben, die Angabe der Parameter page
, per_page
und offset
in der URL.
Es gilt:
- per_page
(int)
Anzahl der Treffer pro Seite. - offset
(int)
Der Startpunkt bzw. der Versatz. - page
(int)
Die Seite.
Wenn wir pro Seite nur einen Treffer zurückgeben wollen und uns auf der zweite Seiten befinden, könnte man folgendes schreiben um den zweiten Post zu erhalten:
GET http://test.local/wp-json/wp/v2/posts?per_page=1&page=2
Das gleiche Ergebnis würde man mit folgendem Aufruf erhalten:
GET http://test.local/wp-json/wp/v2/posts?per_page=1&offset=1&page=1
Durch offset=1
wurde die Ergebnisliste um 1 verschoben. Wir erhalten auf Seite 1 also den zweiten Beitrag.
Hinweis
Der Parameterper_page
wurde intern aus Performancegründen auf das Limit von 100 begrenzt.
Für die Gesamtzahl der vorhandenen Einträge muss man nicht zwingend eine neue Abfrage starten. Diese liefert die REST-API nämlich bereits mit, wenn der page
-Parameter angehängt wurde. Und zwar im Antwort-Header:
X-WP-Total →2
X-WP-TotalPages →2
Hinweis
Wenn Sie die Antwort-Header nicht auslesen können, nutzen Sie den_envelope
-Parameter wie oben beschrieben.
Sortierung
Ähnlich der Paginierung gibt es zwei Parameter, die Ergebnisse sortieren lassen:
- order
(string)
asc
(aufsteigend) oderdesc
(absteigend). Standard istdesc
. - orderby
(string)
Der Parameter nach dem geordnet werden soll. Diese können, je nach Abfrage, unterschiedlich sein. Sehen Sie sich dazu bitte die Schemata der einzelnen Routen genauer an.
Beispiel:
GET http://test.local/wp-json/wp/v2/posts?order=desc&orderby=id
Ordnet alle Beiträge absteigend nach deren ID.
API-Discovery
Man kann testen, ob die REST-API einer Website aktiviert ist oder nicht. Dazu sendet man einen HEAD-Request an die jeweilige Seite:
HEAD http://test.local
Man erhält unter anderem folgende Information im Antwort-Header zurück:
Link →<http://test.local/wp-json/>; rel="https://api.w.org/"
Wenn man keinen HEAD-Request senden kann, geht es auch mit GET. Allerdings muss man dann den zurückkommenden HTML-Code analysieren:
GET http://test.local
Im <head>
-Bereich der Website sollte man dann folgendes finden:
<link rel='https://api.w.org/' href='http://test.local/wp-json/' />
Auch über die XMLRPC-Schnittstelle (falls aktiv) lässt sich die URL zur REST-API herausfinden:
GET http://test.local/xmlrpc.php?rsd
gibt folgendes zurück:
<?xml version="1.0" encoding="UTF-8"?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
<service>
<engineName>WordPress</engineName>
<engineLink>https://wordpress.org/</engineLink>
<homePageLink>http://test.local</homePageLink>
<apis>
...
<api name="WP-API" blogID="1" preferred="false" apiLink="http://test.local/wp-json/" />
</apis>
</service>
</rsd>
Extension-Discovery
Wenn man die URL zur REST-API herausgefunden hat (siehe oben), kann man automatisiert herausfinden, was denn alles möglich ist (welche Funktionen die Schnittstelle bietet).
Dazu sendet man initial eine Abfrage an die API:
GET http://test.local/wp-json
und liest den namespace
-Parameter aus:
{
"url": "http://test.local",
...
"namespaces": [
"oembed/1.0",
"wp/v2"
],
...
}
Durch weitere Abfragen erhält man schließlich alle Routen zu den Namespaces:
GET http://test.local/wp/v2
ergibt:
{
"namespace": "wp/v2",
"routes": {
"/wp/v2": {
"namespace": "wp/v2",
"methods": [
"GET"
],
"endpoints": [
{
"methods": [
"GET"
],
"args": {
"namespace": {
"required": false,
"default": "wp/v2"
},
"context": {
"required": false,
"default": "view"
}
}
}
],
...