Repository navigation
docs: add API v1 contract (docs/api.md) - #8
Conversation
One file with every request and response shape, followed by both the API and the dashboard. Adopts the nested event/endpoint objects and the attempt_log name proposed in PR #7, and clarifies replay, endpoint status, the /v1/me answer and attempt error codes.
AbdikhaniAbdirashid
left a comment
There was a problem hiding this comment.
Read it against all four screens - they can be built from these shapes alone. The attempts vs attempt_log section settles what I got wrong in #7.
Three questions, none blocking:
-
CORS. The table says cdn.myrelay.tech "and localhost in CI". Does that mean localhost:5173 cannot call the real API while I develop? If so I need to run the API locally once I move off mock data - better to know now than later.
-
in_flight. Replay can answer 409 in_flight, but no field on Delivery says a worker is sending right now, so the Replay button cannot be greyed out up front. It has to fire, get the 409 and show the error. Fine by me, just confirming that is intended.
-
disabled is unreachable. active and failing are derived from deliveries, but disabled needs someone to choose it, and there is no PATCH and no DELETE. So one of the three values can never occur in v1.
My suggestion: drop disabled from EndpointStatus for now and keep it with DELETE under "later". No screen needs it yet, failing already tells me a receiver is down, and the circuit breaker you listed is the real answer anyway.
One thing that may matter sooner: with a hard limit of 20 endpoints and no DELETE, a few typos while testing burn slots permanently. Is 20 generous enough to live with before the defense?
|
Thanks for checking it against all four screens. Good questions, and all three are now in #10:
Right, the real API only accepts browser calls from server: { proxy: { "/v1": { target: "https://api.myrelay.tech", changeOrigin: true } } }and leave
Yes, intended. A send takes at most a few seconds, so it's rare. On
Agreed on both. #10 adds |
Follow-up to #8, answering the three review questions there. ## Changes to `docs/api.md` - **`DELETE /v1/endpoints/:id` is now part of v1.** It's a soft delete: the endpoint disappears from the list and frees its slot, but its old deliveries still show its name and URL. Deliveries still pending for it become `dead` with `last_error: "endpoint_deleted"`. Without it, test typos would use up the 20 slots for good. - **`EndpointStatus` is `active | failing`.** `disabled` could never occur in v1. Deleted endpoints simply aren't listed. - **New error codes:** - `409 endpoint_limit_reached` when creating a 21st endpoint; - `409 endpoint_deleted` when replaying a delivery whose endpoint was deleted. - **Replay:** the dashboard can't know in advance that a delivery is being sent right now, so the button tries, and a `409 in_flight` is shown as "being sent right now, try again in a moment". - **CORS and local development:** browsers may call the API only from `https://cdn.myrelay.tech` and `http://localhost:4173` (Playwright's preview server in CI). For local development, the Vite dev server proxies `/v1` to the API, so CORS never applies. The config snippet is in the doc. `docs/CONTEXT.md` lists the new route. The types block in `docs/api.md` compiles with strict TypeScript.
Updated to match `docs/api.md` (#8), as requested. - `dashboard/src/types.ts` — the types block from `docs/api.md`, copied over. Not a proposal any more. - `dashboard/src/mocks.ts` — fake data shaped to those types, for building the four screens before the API exists. ## Your review points | # | Done | |---|---| | 1 | Tool attribution gone from the commit and from this description | | 2 | Replay resets `attempts` to 0; `attempt_log` keeps its eight rows | | 3 | `status: active \| failing` on endpoints; `GET /v1/endpoints` returns `{ data }` with no paging | | 4 | `me` is `{ owner: { id, name }, key: { prefix } }` | | 5 | Attempt errors are `AttemptError` codes, `null` when the receiver answered | | 6 | `ApiError.details` added, with 401 and both 409 bodies as fixtures | | 7 | Timelines add up, `example.com` URLs, `whsec_MOCK_not_a_real_secret`, header points at `docs/api.md` | ## On the timelines Every gap in an attempt log starts when the previous try **ended** (`started_at + duration_ms`) and follows the retry schedule. The dead delivery's eight tries are exact to the millisecond, and the pending delivery's three tries total 10.350 s, which is what makes its `next_attempt_at` land five minutes after try 3. ## What the mocks cover | Fixture | Why | |---|---| | pending, 3 tries | the row the detail screen reloads every 2 s | | dead, 8 tries | the exhausted-budget example; pending can be replayed too | | delivered, 1 try | the common case | | delivered, 2 tries | `attempts > 1` can still end well | | dead, endpoint_deleted | soft-deleted endpoint example; endpoint is missing from the list | | 3 endpoints | two active/failing, one shown on Create form response | | 401, 409 ×3, 422 | Connect (401), Replay (409 in_flight/already_delivered/endpoint_deleted), Create (409 endpoint_limit_reached), Add form (422) | Endpoint `status` is derived the way `docs/api.md` says: n8n is `failing` because its latest delivery is pending after a failed try; Slack is `active` because its latest went through. ## Checked `tsc --noEmit` passes. All 27 ids are valid UUIDv7 with valid variant bits. ## Not covered on purpose No `EventAccepted` fixture — no screen posts events. No pagination fixture — four rows is under the default limit of 50. --------- Co-authored-by: Abdikhani Abdirashid <Abdikhani_abdirashd@hotmail.com>
Adds
docs/api.md: the API v1 contract with every request and response shape, so the API and the dashboard build against one file instead of two descriptions that drift apart. This moves the planned "API contract" step earlier, because the dashboard needs it now.What's in it
X-Request-Id, 404 for other owners' ids, CORS.detailson 422, and the full list of status codes andcodevalues.{ data, next_cursor }, newest first.src/types.ts.Adopted from PR #7
eventandendpointobjects in delivery rows, instead of flatevent_type/endpoint_name. It matches the detail answer and reads better in the dashboard. The API maps database rows to this shape in its service layer.attempt_logfor the history of tries. The earlier draft usedattemptsfor both the counter and the list.Clarified
attemptsto 0. The history (attempt_log) is never deleted, and tries keep their numbers.status(active/failing/disabled), worked out when the list is read.GET /v1/mereturns the owner and the key prefix.timeout,connect_failed,blocked_address,redirect,tls);nullwhen the receiver answered with a status code.next_attempt_atisnullunless the delivery is pending.docs/CONTEXT.mdnow points to the new file.How to review
Read
docs/api.mdtop to bottom and check that the dashboard screens can be built from these shapes alone. Once merged, PR #7 can aligndashboard/src/types.tsto it.