Daten von einer API abrufen
Verwenden Sie den Hook useFetch, wann immer Ihr Widget Daten von einer API braucht.
import { useFetch } from "~lib/use-fetch";
type Weather = {
readonly temperature: number;
};
export const Widget = () => {
const { data } = useFetch<Weather>("https://api.example.com/weather");
return <div className="text-6xl">{data.temperature}°C</div>;
};
Ihr Widget wartet auf die Daten, bevor es gezeichnet wird. data ist also immer vorhanden, und es gibt keinen Ladezustand, den Sie prüfen müssten.
Verwenden Sie useFetch statt fetch aus dem Browser. Anfragen laufen über die Server von Blotch. Deshalb funktionieren auch APIs, die Anfragen aus einem Browser blockieren.
Die Antwort typisieren
Übergeben Sie die Form der Antwort als Typparameter, dann bekommen Sie für data die volle Autovervollständigung:
type Quote = {
readonly text: string;
readonly author: string;
};
const { data } = useFetch<Quote[]>("https://api.example.com/quotes");
data[0].author; // string
Sie müssen den Typ nicht von Hand schreiben. Wählen Sie im Widget-Studio auf dem Tab Netzwerk neben einer Antwort Typdefinitionen erstellen, um einen TypeScript-Typ dafür zu kopieren.
Eingaben verwenden
Lesen Sie Ihre Eingaben mit useInputs und bauen Sie sie in die URL ein. Packen Sie alles, was jemand eintippt, in encodeURIComponent, damit Leer- und Sonderzeichen erhalten bleiben:
import { useFetch } from "~lib/use-fetch";
import { useInputs } from "~lib/use-inputs";
export const Widget = () => {
const { CITY } = useInputs();
const { data } = useFetch<Weather>(
`https://api.example.com/weather?city=${encodeURIComponent(CITY)}`,
);
return <div>{data.temperature}°C</div>;
};
API-Schlüssel
Schreiben Sie nie einen API-Schlüssel in Ihren Widget-Code, denn Widget-Code ist öffentlich. Speichern Sie ihn als Private Eingabe und senden Sie ihn in einem Header:
const { API_KEY } = useInputs();
const { data } = useFetch<Weather>("https://api.example.com/weather", {
headers: { "X-Api-Key": API_KEY },
});
Für Dienste, bei denen man sich mit OAuth anmeldet, etwa Google oder Spotify, verwenden Sie stattdessen eine Integration.
Daten senden
Das zweite Argument nimmt dieselben Optionen wie fetch im Browser, etwa method, headers und body:
const { data } = useFetch<SearchResult>("https://api.example.com/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: "weather" }),
});
body kann Text sein, etwa JSON, oder URLSearchParams bzw. FormData, um ein Formular zu senden. Dateien lassen sich nicht senden.
Jede Anfrage gleich halten
Ihr Widget-Code kann mehrmals laufen, während er auf Daten wartet, und jede Antwort geht nur an genau die Anfrage zurück, die sie angefordert hat. Bauen Sie deshalb jedes Mal dieselbe URL, dieselben Header und denselben Body.
Eine zufällige ID oder die aktuelle Uhrzeit fällt bei jedem Lauf anders aus, deshalb wird die Antwort darauf nie verwendet. Nach einigen Versuchen fragt Blotch nicht mehr an und zeigt statt Ihres Widgets einen Fehler an. Erzeugen Sie einen solchen Wert einmal, außerhalb Ihres Widgets:
const DEVICE_ID = Math.random().toString(36).slice(2);
export const Widget = () => {
const { data } = useFetch<Session>("https://api.example.com/sessions", {
method: "POST",
body: JSON.stringify({ deviceId: DEVICE_ID }),
});
return <div>Signed in as {data.name}</div>;
};
Auch useState behält ihn nicht, denn React setzt den Zustand Ihres Widgets zurück, solange es auf seine ersten Daten wartet.
Eine Anfrage nach der anderen
Da data immer vorhanden ist, kann eine zweite Anfrage das Ergebnis der ersten verwenden:
const { data: user } = useFetch<User>("https://api.example.com/me");
const { data: posts } = useFetch<Post[]>(
`https://api.example.com/users/${user.id}/posts`,
);
Die Anfragen laufen nacheinander, sodass jede einzelne die Vorbereitung Ihres Widgets verlängert. Rufen Sie nur ab, was Sie auch anzeigen.
Caching
Übergeben Sie proxyCache mit einer ttl in Millisekunden, dann speichert Blotch die Antwort so lange:
const { data } = useFetch<Weather>("https://api.example.com/weather", {
proxyCache: { ttl: 30 * 60 * 1000 }, // 30 Minuten
});
Bis die ttl abläuft, bekommt jede identische Anfrage, egal von welchem Rahmen, die gespeicherte Antwort, statt die API erneut zu fragen. Eine Anfrage ist identisch, wenn URL, Methode, Header und Body übereinstimmen. Alle Rahmen, die das Wetter in London zeigen, teilen sich also eine Antwort, und Paris bekommt eine eigene.
Nutzen Sie den Cache, wenn sich die Daten langsam ändern, etwa beim Wetter oder bei Schlagzeilen, oder wenn die API langsam ist, die Zahl der Anfragen begrenzt oder pro Anfrage Geld kostet. Für Daten, die immer aktuell sein müssen, lassen Sie ihn weg.
- Private Anfragen werden nie zwischengespeichert. Eine Anfrage mit einem Header
Authorization,Proxy-Authorization,CookieoderX-Api-Keygeht immer an die API, denn ihre Antwort könnte einer einzelnen Person gehören. Einen Schlüssel in der URL kann Blotch nicht erkennen. Speichern Sie deshalb nur Antworten zwischen, die für alle gleich sind. - Auch Fehler werden zwischengespeichert. Mit einer kürzeren
ttlist eine fehlerhafte Antwort schneller wieder verschwunden. - Der Cache lässt sich nicht vorzeitig leeren, und eine sehr lange
ttlwird auf das Maximum gekürzt, das Blotch zulässt.
Fehler
data enthält, was auch immer die API zurückgeschickt hat, selbst einen Fehler wie 404 Not Found. Wenn die API ein eigenes Fehlerformat hat, prüfen Sie darauf:
type WeatherResponse =
| { readonly temperature: number }
| { readonly error: { readonly message: string } };
export const Widget = () => {
const { data } = useFetch<WeatherResponse>("https://api.example.com/weather");
if ("error" in data) {
return <div>Weather unavailable: {data.error.message}</div>;
}
return <div>{data.temperature}°C</div>;
};
Kann die Anfrage gar nicht erst gestellt werden, etwa weil die API ausgefallen ist, zeigt Blotch den Fehler statt Ihres Widgets an. Darum müssen Sie sich nicht selbst kümmern.
Anfragen kommen von den Servern von Blotch, nicht vom Rahmen. Deshalb erreichen sie keine Adressen in einem Heimnetz wie 192.168.1.10.
Erneut versuchen
Manche APIs antworten „wird noch bearbeitet“ und erwarten, dass Sie erneut fragen. Geben Sie retry eine condition, die bei solchen Antworten true zurückgibt. Dann wartet useFetch und fragt erneut, höchstens so oft, wie count angibt:
const { data } = useFetch<Report>("https://api.example.com/report", {
retry: {
condition: (report) => report.status === "pending",
count: 5,
},
});
Antwortformate
- JSON wird für Sie geparst.
- Antworten in XML, RSS und Atom, die mit
<?xmlbeginnen, werden zu einfachen Objekten. Elemente werden zu Schlüsseln, und Attribute werden zu Schlüsseln, die mit@_beginnen. Aus<rss version="2.0">wird alsodata.rss["@_version"]. - Alles andere, etwa reiner Text oder HTML, kommt als
stringan.
Wenn die Antworten einer XML-API nicht mit <?xml beginnen, setzen Sie output: "force", um sie trotzdem umzuwandeln. Mit output: "pass-through" bleibt XML Text.
Alle Optionen finden Sie unter useFetch in der Referenz.