28. RESTful APIs with .NET
Answer as submitted
“Yes — I have designed and implemented RESTful APIs in .NET/ASP.NET Core, from endpoints and contracts through security, testing and deployment.”
Expanded answer
Yes, on ASP.NET Core. The API is designed resource-first: URLs are nouns, the hierarchy lives in the path, and a state transition is modelled as a sub-resource that receives a POST rather than a verb grafted onto the URL. The HTTP method carries the meaning — GET, PUT, DELETE and HEAD are idempotent, POST is not, a state conflict answers 409 while a failed precondition answers 412 and a missing one 428 — so a client can retry safely without reading the documentation. Collections are never returned unbounded: cursor pagination with a hard page-size ceiling and a documented filter/sort grammar. Every failure returns one payload shape, RFC 7807 problem details with a type, a title, a status and a traceId that matches the server log. Security is explicit per endpoint (a bearer JWT validated against the issuer's JWKS, an authorisation policy, a per-caller rate limit) and identity always comes from validated claims, never from the body. Finally, the OpenAPI document is generated from the endpoints, the SPA consumes a typed client generated from that document, and contract plus integration tests through WebApplicationFactory against a containerised database fail the build when the two drift apart.
| Concern | Convention I apply | Why it matters |
|---|---|---|
| Resource model | nouns in the path, hierarchy expressed in the URI, transitions as sub-resources | the API reads as a map of the domain instead of a list of procedures |
| Methods and status codes | GET/PUT/DELETE idempotent, POST not, 201 + Location, 204 on delete, 409 / 412 / 428 for state and precondition failures | clients and proxies can retry correctly without reading the docs |
| Collections | cursor pagination, hard page-size ceiling, one filter and sort grammar | no endpoint can be used to pull the whole table by accident |
| Errors | RFC 7807 problem details for every failure mode, with a traceId | one parser on the client and one correlation key in the logs |
| Security | explicit policy per endpoint, JWT claims as the identity source, per-caller rate limit, CORS allow-list | identity cannot be spoofed through the payload and abuse is bounded |
| Contract and verification | OpenAPI generated from code, typed client for the SPA, contract + integration tests in CI | the documented contract is the tested contract |
Live REST design workflow proof
The running component below changes its design/result view through real event binding. Select a step to see the decision, the reasoning behind it, and the evidence that the API actually behaves that way.
Choose a step of the API design
Select a step to inspect the decision, the reasoning and the evidence.
$ POST /orders · GET /orders/{orderId} · GET /orders/{orderId}/lines · POST /orders/{orderId}/confirm
Resources are nouns and the hierarchy lives in the path. The one verb-like segment is a state transition, and it is modelled as a sub-resource that receives a POST instead of inventing /confirmOrder. Every path resolves to exactly one aggregate.
aggregates exposed: 2 (order, order lines) verbs appearing in a URI: 0 state transitions modelled as sub-resources: 1
What the API design buys
Source files
Select a file to inspect the proof with syntax highlighting and line numbers. The first file is the code running the component above; the others are the published contract, the ASP.NET Core endpoints and the contract tests that hold the two together.
Acceptance criteria
- Models resources as nouns and expresses state transitions as sub-resources.
- Makes the idempotency of each method real, with the matching status codes.
- Shows an interactive proof of choosing a design step and reading the evidence.
- Bounds collections, standardises errors on RFC 7807 and never discloses another tenant's resource.
- Ties the implementation to the published contract with tests that fail on drift.