Eine Alternative zu JSONPlaceholder, die Schreibzugriffe speichert
Dieselben Arten von Ressourcen, aber Schreibzugriffe werden gespeichert, schlechte Eingaben abgelehnt und Fehler gibt es auf Wunsch.
Beispiele zuletzt am gegen die API ausgeführt
JSONPlaceholder täuscht seine Schreibzugriffe nur vor: Ein POST liefert id: 101, aber ein GET auf diese ID liefert 404, und ein DELETE lässt den Datensatz stehen. Wenn deine App zurücklesen muss, was sie gerade geschrieben hat, nimm https://api.testingapis.com/apianmelden zum Anzeigen. Sie hat dieselben Arten von Ressourcen (Posts, Kommentare, Alben, Fotos, Todos und Benutzer), und Anlegen, Ändern und Löschen werden gespeichert. Außerdem lehnt sie ungültige Eingaben mit 400 ab und kann jeden Request auf Wunsch scheitern lassen, du kannst also auch die Fehlerzustände bauen und testen. Kostenlos, ohne Schlüssel und für Requests von jedem Origin offen.
Schreibzugriffe, die gespeichert werden
Das macht JSONPlaceholder mit einem neuen Post:
$ curl -X POST https://jsonplaceholder.typicode.com/posts \
-H "Content-Type: application/json" \
-d '{"title":"hello","body":"world","userId":1}'
{ "title": "hello", "body": "world", "userId": 1, "id": 101 }
$ curl -i https://jsonplaceholder.typicode.com/posts/101
HTTP/1.1 404 Not FoundDieselben Schritte hier: einen Post anlegen, zurücklesen, bearbeiten, löschen und prüfen, dass er weg ist.
$ curl -X POST https://api.testingapis.com/api/Posts \
-H "Content-Type: application/json" \
-d '{"userId":101,"title":"Hello from the guide","body":"Checking that writes persist."}'
{"message":"Post created successfully","data":{"id":16,"userId":101,"title":"Hello from the guide","body":"Checking that writes persist.","tags":[],"publishedAt":"2026-10-07T02:58:58Z","likes":0}}
$ curl https://api.testingapis.com/api/Posts/16
{"id":16,"userId":101,"title":"Hello from the guide","body":"Checking that writes persist.","tags":[],"publishedAt":"2026-10-07T02:58:58Z","likes":0}
$ curl -X PUT https://api.testingapis.com/api/Posts/16 \
-H "Content-Type: application/json" \
-d '{"userId":101,"title":"Edited title","body":"Checking that writes persist."}'
{"message":"Post updated successfully","data":{"id":16,"userId":101,"title":"Edited title",...}}
$ curl -X DELETE https://api.testingapis.com/api/Posts/16
{"message":"Post deleted successfully"}
$ curl -i https://api.testingapis.com/api/Posts/16
HTTP/1.1 404 Not Found
{"status":404,"error":"Not Found","message":"Post with ID 16 does not exist."}Zuordnung der Routen
| JSONPlaceholder | testingapis.com | Datensätze |
|---|---|---|
/posts | /api/posts | 15 (JSONPlaceholder: 100) |
/posts/1/comments | /api/posts/1/comments | Kommentare zu Post 1 |
/comments | /api/commentsdocs | 50 (500) |
/albums | /api/albumsdocs | 10 (100) |
/albums/1/photos | /api/albums/1/photosanmelden zum Anzeigen | 5 pro Album |
/photos | /api/photosdocs | 50 (5.000) |
/todos | /api/todos | 30 (200) |
/users | /api/peopledocs | 20 (10), mit Adresse, Geodaten und Firma |
/users/1/posts | /api/posts/user/101 | Benutzer-IDs beginnen bei 101 |
Pfade unterscheiden keine Groß- und Kleinschreibung: /api/posts und /api/Posts sind dasselbe. Es gibt weniger Datensätze als bei JSONPlaceholder, dafür hat jeder mehr Felder. Posts haben Tags, Likes und ein Veröffentlichungsdatum, Todos eine Priorität und ein Fälligkeitsdatum, und Personen eine verschachtelte Adresse und Firma. Die API-Dokumentation listet 13 weitere Ressourcentypen, von Produkten und Warenkörben bis zu Büchern, Filmen und Ländern.
/api/posts/1Schlechte Eingaben bekommen einen Fehler
JSONPlaceholder nimmt jeden Body an, sogar einen leeren. Hier liefert ein fehlendes Pflichtfeld 400 mit einer Meldung, der Fehlerzweig deines Formulars hat also etwas Echtes zum Anzeigen:
$ curl -i -X POST https://jsonplaceholder.typicode.com/posts -H "Content-Type: application/json" -d '{}'
HTTP/1.1 201 Created
{ "id": 101 }
$ curl -i -X POST https://api.testingapis.com/api/Posts -H "Content-Type: application/json" -d '{"title":""}'
HTTP/1.1 400 Bad Request
{"status":400,"error":"Bad Request","message":"Missing required field: title"}Fehler und langsame Antworten auf Wunsch
Hänge ?error=500 an einen beliebigen Request, damit er mit diesem Status scheitert, oder ?delay=3, damit er drei Sekunden zu spät antwortet. Zusammen zeigt ?delay=2&error=503 einen Ladezustand, gefolgt von einem Fehler. Der Leitfaden zu Fehlerantworten behandelt Timeouts, Retries und Rate Limits.
/api/todos/1?error=503Filtern, Sortieren und Paginieren
Beide APIs filtern Listen nach Feldern, etwa mit ?userId=101, und beide sortieren, suchen und paginieren. Die Parameternamen unterscheiden sich:
| JSONPlaceholder | testingapis.com | |
|---|---|---|
| Filtern | ?userId=1 | ?userId=101 |
| Seite | ?_page=2&_limit=10 | ?page=2&limit=10 |
| Sortieren | ?_sort=id&_order=desc | ?sort=id&order=desc |
| Suchen | ?q=word | ?q=word |
| Gesamtzahl | X-Total-Count | X-Total-Count, X-Total-Pages |
Eine App umstellen
Lesezugriffe liefern den Datensatz direkt, wie bei JSONPlaceholder. Schreibzugriffe verpacken ihn mit einer Meldung als { message, data }, und Benutzer-IDs beginnen bei 101. Das sind die zwei Änderungen, die die meisten Apps brauchen:
// Before
const BASE = "https://jsonplaceholder.typicode.com";
const post = await (await fetch(`${BASE}/posts/1`)).json();
const created = await (await fetch(`${BASE}/posts`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: 1, title: "Hi", body: "There" }),
})).json();
// After
const BASE = "https://api.testingapis.com/api";
const post = await (await fetch(`${BASE}/posts/1`)).json();
const { data: created } = await (await fetch(`${BASE}/posts`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: 101, title: "Hi", body: "There" }),
})).json();Wann JSONPlaceholder die bessere Wahl ist
- Du brauchst große Listen, etwa 5.000 Fotos, um virtuelles Scrollen zu testen.
- Du folgst einem Tutorial, das genau die IDs und Felder von JSONPlaceholder nutzt.
- Du liest nur Daten und brauchst nie, dass ein Schreibzugriff danach sichtbar ist.
Um weiterzugehen, zeigt die Lektion zum CRUD-Testing, wie du prüfst, dass jedes Anlegen, Ändern und Löschen wirklich passiert ist.