Skip to main content
One idea at a time

HTTP is the agreement between client and server

An API contract tells your frontend what to send and what a response means. TypeScript interfaces inside the frontend cannot define that agreement by themselves. The request crosses a network, and another client can send different data.

Taskboard exposes resources under /api. A workspace owns projects, and a project owns tasks. The route expresses that relationship.

GET /api/workspaces/workspace-id/projects/project-id/tasks HTTP/1.1

GET reads a resource. It must not create a task or send an invitation. Browsers, proxies, and clients can repeat reads, sometimes without a fresh user gesture.

POST asks the server to perform an operation such as creating a task. PATCH changes selected fields of an existing task. DELETE removes a resource. These method names help clients reason about behavior, but the server still has to implement the intended guarantees.

Status and body have different jobs​

The status gives the broad result. The JSON body gives application details. Common results in Taskboard include an authentication failure, a forbidden role, an unavailable resource, and a conflict with a newer task version.

An error response follows this shape:

{
"error": {
"code": "SOME_STABLE_ERROR_CODE",
"message": "A human-readable explanation"
},
"requestId": "request-identifier"
}

This is an illustrative error, not a specific endpoint response. Frontend logic can branch on a stable code. People can read the message. The request identifier lets support locate the corresponding server logs.

Headers carry information outside the resource body. Content-Type describes the body format. A cookie carries the session credential. X-CSRF-Token protects authenticated writes made through the browser. Idempotency-Key identifies a retryable operation.

A route is input​

A UUID in the URL identifies a record. It does not prove that the caller can access the record. Changing the workspace or task identifier is a normal capability of an HTTP client, even when the frontend hides those fields.

A common frontend mistake is treating every non-success response as a network failure. A 409 conflict needs different handling from an unreachable server. The first gives a known outcome. The second may leave the outcome uncertain.

Why include a workspace identifier if the task has a globally unique ID?

The workspace makes the intended tenant context explicit. The server still checks membership and constrains the query to that workspace.

Read an HTTP request as a complete agreement: method, path, headers, body, and documented response.

Read api/src/app.ts