Area: pipes
With #634 (in review), a pipe whose SQL is a write runs on every call, and is neither cached nor coalesced (#386). It can still be called with GET /v1/pipes/{name}. Along the way, GET is treated as safe and idempotent, so a single call can turn into several writes:
- A reverse proxy retries a failed GET on the next upstream (nginx's default
proxy_next_upstream), but not a POST.
- Go's
http.Transport may resend a GET without a body when a reused connection dies.
- Link unfurlers and prefetchers fetch GET URLs.
?token= puts the credential in the URL, so a pasted link carries its own authorization.
Each replay is another write: the mirror image of #386.
Proposal: when a write pipe is called with GET, answer 405 Method Not Allowed with Allow: POST. The handler already classifies the bound SQL. The TS SDK already calls pipes with POST (clients/ts/src/pipes.test.ts: "fetch() POSTs to /v1/pipes/{name}"), so it is unaffected. Document the rule in pipes.mdx ("Pipes that write") and in api.md.
Area: pipes
With #634 (in review), a pipe whose SQL is a write runs on every call, and is neither cached nor coalesced (#386). It can still be called with
GET /v1/pipes/{name}. Along the way, GET is treated as safe and idempotent, so a single call can turn into several writes:proxy_next_upstream), but not a POST.http.Transportmay resend a GET without a body when a reused connection dies.?token=puts the credential in the URL, so a pasted link carries its own authorization.Each replay is another write: the mirror image of #386.
Proposal: when a write pipe is called with GET, answer
405 Method Not AllowedwithAllow: POST. The handler already classifies the bound SQL. The TS SDK already calls pipes with POST (clients/ts/src/pipes.test.ts: "fetch() POSTs to /v1/pipes/{name}"), so it is unaffected. Document the rule inpipes.mdx("Pipes that write") and inapi.md.