Caching und Aktualisierung
Sie durfen den Katalog lokal spiegeln. Diese Seite nennt die Aufbewahrungsdauer je Antworttyp, zeigt, wie Sie ohne erneuten Download prufen, ob Ihre Kopie aktuell ist, und was diese Prufung kostet.
Wie lange Sie speichern durfen
Jede Dauer unten ist der Wert, den die API auf diesem Pfad tatsachlich im Cache-Control-Header sendet. Diese Tabelle wird aus derselben Konfiguration erzeugt, mit der der Server seine Antworten stempelt.
| Ressource | Ihr Cache | Gemeinsame Caches | Bedingte Anfragen |
|---|---|---|---|
Reference lists: cartridges, categories, manufacturers, filter options/v1/calibersVocabularies. A new manufacturer appears a few times a year, and nothing downstream breaks if you learn about it an hour late. | 1 hour | 1 day | Unterstutzt |
A random firearm/v1/firearms/randomNon-deterministic by definition. Cached even briefly, every caller would get the same "random" record for the window. | Do not store | - | Nicht angeboten |
Name resolution/v1/firearms/resolveA deterministic lookup over an index of spellings, not over the specifications themselves. The answer to "which firearm is G19" changes only when the catalogue gains a record that competes for the name, and it is the same question asked over and over - so it is the most worthwhile response on the platform to keep. | 1 hour | 1 day | Unterstutzt |
One firearm, manufacturer or cartridge/v1/firearms/ak-47Specifications change when a source is corrected, and a correction is the thing a specification database exists to propagate. Five minutes is short enough that a fix reaches readers the same day; the version field lets you hold it far longer and check cheaply. | 5 minutes | 1 hour | Unterstutzt |
Firearm lists and search/v1/firearmsA page of results depends on filters, sort and what was added today, so it goes stale faster than any single record on it. | 1 minute | 5 minutes | Unterstutzt |
Catalog summary counts/v1/stats/summaryTotals over the whole catalog. Expensive to compute, and nobody is misled by a count that is an hour behind. | 1 hour | 1 day | Unterstutzt |
Other statistics/v1/stats/top-viewedAggregates recomputed from the catalog rather than stored, so the cost of a miss is real and the value of being current is low. | 30 minutes | 1 hour | Nicht angeboten |
Site notices/v1/noticesRead on the first paint of every page. A minute is short enough that pulling a notice down is felt almost immediately, and long enough that it costs one read per location per minute rather than one per visitor. | 1 minute | 1 minute | Nicht angeboten |
Example verification/v1/sdk/verificationThe badge on every SDK page and under every cURL sample. A minute, with a short stale window: a run is published a few times a day and the page exists to show the newest one, so the write purges this key as well - an hour of stale-while-revalidate was long enough to show the previous run after a release. | 1 minute | 1 minute | Nicht angeboten |
Data quality report/v1/data/gapsRecomputed from the whole catalog on every call: a table scan per check, on a keyless endpoint that a public page reads on every visit. The figures move when the catalog is re-seeded, which is hours or days apart, so a minute costs one computation per location per minute and is never meaningfully behind. The window is deliberately short rather than an hour: the page carries a refresh control, and a button whose effect is invisible for the next fifty-nine minutes is worse than no button. | 1 minute | 1 minute | Nicht angeboten |
Data task board/v1/data/tasksThe public half of the remediation queue: that work exists on a finding and where it has got to. A minute, matching the gap report it is generated from, because the two are read together and a board a minute behind the figures beside it would look like a bug. States change when a worker claims or files something, which is minutes or hours apart, so this is never meaningfully stale. | 1 minute | 1 minute | Nicht angeboten |
Contract check results/v1/contractThe smoke suite runs daily, so five minutes is short beside the thing it describes and long enough that a health page costs one read per location. The publish purges this key, which is what makes a re-run visible immediately rather than at the end of the window. | 5 minutes | 5 minutes | Nicht angeboten |
Health checks/healthA cached health check reports the health of the cache. | Revalidate every time | - | Nicht angeboten |
Your account, billing and authentication/user/meAnswers about one person. Never stored anywhere, by us or by anything between us. | Do not store | - | Nicht angeboten |
Das sind die Zeitraume, nach denen Sie erneut prufen sollten, nicht die, nach denen die Daten falsch sind. Mit einer bedingten Anfrage konnen Sie einen Datensatz deutlich langer halten: prufen Sie nach eigenem Zeitplan, ein unveranderter Datensatz kostet Sie eine leere Antwort.
Drei Wege zu prufen, ob Ihre Kopie aktuell ist
Katalogdatensatze fuhren zwei davon im Body, jede Antwort den dritten im Header. Sie beantworten leicht unterschiedliche Fragen, speichern Sie also den passenden.
updatedAt- When the record last changed. Maintained by the database itself, on a content comparison, so re-importing an identical record does not move it, so a timestamp that moved means something a reader can see is different.
version- A short hash of the fields inside the record itself. Equal versions mean equal data. Unlike an ETag it does not vary by plan or by response shape, so it is the value to store beside a mirrored record and compare across tiers.
ETag- A hash of the exact bytes of this response, for this plan. Send it back as If-None-Match. It is per-response, not per-record: two plans see the same record under different tags because they receive different fields.
Datenrevisionen
Was sich bewegt, wenn ein Datensatz korrigiert wird, in einfachen Worten, damit ein Spiegel weiß, was er speichert und worauf er hört. Die API ist getrennt versioniert; Versionierung beschreibt diesen Vertrag.
updatedAtist der Zeitpunkt, an dem sich die gelieferten Spalten zuletzt geändert haben. Die Datenbank pflegt ihn über einen Inhaltsvergleich; kein Schreiber kann ihn setzen, ohne die Daten zu ändern.versionist der Inhalts-Hash des Datensatzes. Gleiche Versionen heißen gleiche Daten, auf jedem Tarif, also ist sie das, was ein Spiegel neben einem Datensatz speichert.- Eine Korrektur an einem Datensatz ändert beides und löst
firearm.updatedbei Abonnenten aus. Wenn sich Belegung oder Wert bewegt haben, kommenfirearm.source.changedundfirearm.confidence.changeddaneben an. - Eine katalogweite Neustempelung, bei der jeder Hash absichtlich neu berechnet wird, kommt als ein einziges
catalog.resyncedstatt als ein Ereignis pro Datensatz. Neu synchronisieren statt anwenden. - Änderungen nur an den Daten, ohne Änderung der API, werden im Changelog unter der Kategorie
dataangekündigt. - Es gibt noch keinen Endpunkt für die Änderungshistorie eines Datensatzes. Ein Datensatz trägt seinen aktuellen Stand und den Moment der letzten Änderung, nicht, was er vorher enthielt.
Fragen ohne Herunterladen
Senden Sie das erhaltene ETag als If-None-Match zuruck. Ware die Antwort byteidentisch, erhalten Sie 304 Not Modified ohne Body.
# 1. Fetch, and keep the ETag the response carried.curl -sS -D - -o firearm.json \ -H "X-API-Key: $GUNSPEC_API_KEY" \ https://api.gunspec.io/v1/firearms/ak-47 | grep -i '^etag:'# etag: "3f9c1a7d5b2e4088" # 2. Ask again with it. Unchanged records answer 304 and send no body.curl -sS -o /dev/null -w '%{http_code} %{size_download} bytes\n' \ -H "X-API-Key: $GUNSPEC_API_KEY" \ -H 'If-None-Match: "3f9c1a7d5b2e4088"' \ https://api.gunspec.io/v1/firearms/ak-47# 304 0 bytesEin 304 zahlt auf Ihr Minutenlimit, nicht auf Ihr Tageskontingent. Haufiges Prufen ist bewusst gunstig; Missbrauch bleibt trotzdem begrenzt.
Einen Spiegel aktuell halten
Die Schleife, die ein Agent uber bereits gehaltene Datensatze fahrt. Heruntergeladen wird nur, was sich geandert hat.
// Refreshing a local mirror without downloading it again.async function refresh(record) { const res = await fetch(`${API}/v1/firearms/${record.id}`, { headers: { 'X-API-Key': key, // The tag you stored alongside the record last time. ...(record.etag ? { 'If-None-Match': record.etag } : {}), }, }) // Your copy is current. No body was sent and none was billed // against your daily quota. if (res.status === 304) return record const body = await res.json() return { ...body.data, etag: res.headers.get('ETag'), // `version` changes only when the data changes, so it survives // a re-serialisation that would move the ETag. version: body.data.version, updatedAt: body.data.updatedAt, }}