mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
fix(api): give the shared write ceiling a code a client can branch on
The eleven single-record writes answered their shared 429 with prose and nothing else, while the envelope's own description tells a client to branch on `meta.errorCode`. On `POST /api/medications/[id]/intake` and `POST /api/cycle/day-logs` a second, narrower bucket can answer 429 as well, so the presence of the rate-limit headers was the only thing telling the two refusals apart. All eleven now carry `record_write.rate_limited`, the catalogue lists it, the published 429 names it, and the contract test fails if a site stops emitting it or the sentence stops publishing it. The same description now states what a client could not predict from "300 requests per 60 seconds": refused requests count too, because the check runs before the body is read.
This commit is contained in:
1 parent
68964b4bac
commit
3ffdfe15a1
15 files changed
+70
-32
No files matched your search
@@ -251,6 +251,7 @@ export const ERROR_CODE_CATALOGUE: Readonly<Record<string, readonly string[]>> =
|
||||
"profile.update.invalidBody",
|
||||
"profile.update.nothingSaved",
|
||||
],
|
||||
record_write: ["record_write.rate_limited"],
|
||||
"report-selection": [
|
||||
"report-selection.body.invalid_json",
|
||||
"report-selection.body.invalid_shape",
|
||||
|
||||
@@ -312,7 +312,7 @@ export const stdResponses = {
|
||||
export const recordWriteRateLimitResponse = {
|
||||
"429": {
|
||||
description:
|
||||
"Rate limit exceeded. This route shares one per-account bucket with the other single-record writes — `record-write:<accountId>`, 300 requests per 60 seconds — keyed on the ACTING account, so a delegate burns their own allowance rather than the record owner's. Nothing was written. The `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers describe that bucket; back off on `Retry-After` rather than guessing. A client with more than a handful of rows to send should use the batch endpoint for its domain instead of looping this one.",
|
||||
"Rate limit exceeded. This route shares one per-account bucket with the other single-record writes — `record-write:<accountId>`, 300 requests per 60 seconds — keyed on the ACTING account, so a delegate burns their own allowance rather than the record owner's. Nothing was written. `meta.errorCode` is `record_write.rate_limited`, which is what tells this refusal apart from a route's own narrower bucket when both can answer 429. The `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers describe that bucket; back off on `Retry-After` rather than guessing. Every request counts against the bucket, refused ones included: the check runs before the body is read, so a client looping on a 422 spends the same allowance as one that writes rows. A client with more than a handful of rows to send should use the batch endpoint for its domain instead of looping this one.",
|
||||
content: { "application/json": { schema: errorEnvelope } },
|
||||
headers: stdResponses["429"].headers,
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user