.NET Academy

Designing REST APIs

Model resources, choose methods and status codes, and handle pagination, errors and idempotency.

13 min read

You will learn

  • Design resource-oriented URLs
  • Map operations to HTTP methods and status codes
  • Design pagination, filtering and error responses
  • Explain idempotency and why it matters for retries

What an API is

An API (Application Programming Interface) is a contract that lets programs talk to each other. A web API exposes your backend's capabilities over HTTP so that your frontend, mobile apps, partners — or other backend services — can use them.

The most common style is REST (Representational State Transfer). Its core ideas:

  1. Expose resources (customers, orders, products) at URLs.
  2. Use the HTTP methods for actions, and status codes for outcomes.
  3. Each request is stateless and self-contained.
  4. Exchange representations of resources — usually JSON.

Resources and URLs

URLs are nouns, usually plural, nested where there's a clear ownership:

✅ Good❌ Avoid
GET /productsGET /getAllProducts
GET /products/42GET /product?id=42&action=get
POST /ordersPOST /createOrder
GET /customers/7/ordersGET /ordersOfCustomer/7
POST /orders/42/cancellationPOST /cancelOrder?id=42

Actions that don't fit CRUD (cancel, refund, publish) can be modeled as sub-resources: create a cancellation of an order.

Methods and status codes together

OperationRequestSuccess response
ListGET /products?category=books200 OK + array
Read oneGET /products/42200 OK, or 404 Not Found
CreatePOST /products + JSON body201 Created + Location: /products/43 + the new resource
ReplacePUT /products/42 + full body200 OK (or 204 No Content)
Partial updatePATCH /products/42 + changed fields200 OK
DeleteDELETE /products/42204 No Content

Common failure codes: 400 invalid input, 401 not authenticated, 403 not allowed, 404 not found, 409 conflict (e.g. duplicate email, outdated version), 422 semantically invalid, 429 too many requests, 500 server bug, 503 temporarily unavailable.

Try the contract

Use the mock todo API: create, update and delete todos, and see which status codes and headers come back — including what happens with invalid data or a missing token.

Interactive

HTTP Playground

Send requests to a mock todo API at https://api.example.com — it runs in your browser

Server state: 2 todos — #1 ✓ Learn HTTP, #2 ○ Build an API

Errors: Problem Details

Return errors in a consistent, machine-readable shape. The standard is Problem Details (RFC 9457), which ASP.NET Core produces for you:

{
  "type": "https://example.com/errors/validation",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "quantity": ["Quantity must be at least 1."],
    "email": ["'ada@' is not a valid email address."]
  }
}

Never leak stack traces or SQL to clients — log them on the server instead.

Filtering, sorting and pagination

Collections can be huge, so never return "everything":

GET /products?category=books&sort=-price&limit=20
  • Offset pagination: ?page=3&pageSize=20 — simple, but deep pages are slow and items shift when data changes.
  • Cursor pagination: ?limit=20&after=eyJpZCI6MTIzNH0 — the response includes a next cursor; stable and fast. Used by most large APIs.

Return paging metadata in the body ("next": "/products?after=...") or headers (Link).

Idempotency: safe to retry

Networks fail. If a client's request times out, did it succeed or not? Retrying is only safe if the operation is idempotent — repeating it has the same effect as doing it once:

  • GET, PUT, DELETE are idempotent by definition.
  • POST usually isn't: retrying "create payment" could charge twice.

For non-idempotent operations, APIs accept an idempotency key: the client generates a unique id per logical operation, and the server remembers which keys it has already processed.

POST /payments
Idempotency-Key: 5c1f9a7e-6a2b-4d0e-9e0b-1f8f3c7a2d11

Versioning

APIs evolve, but published clients don't update instantly. Avoid breaking changes (removing fields, changing types); add instead. When you must break things, version: /v2/orders or a header like Api-Version: 2.

Key takeaways

  • Resources are nouns at URLs; HTTP methods are the verbs; status codes report outcomes.
  • 201 Created + Location for creation, 204 for deletes, 4xx for client errors, Problem Details for error bodies.
  • Paginate collections — cursors scale best.
  • Make retried operations safe with idempotent methods or idempotency keys, and version carefully.

Quiz

4 questions · 3 correct to pass
  1. 1.Which URL design is most RESTful for "the orders of customer 7"?

  2. 2.Which methods are idempotent — repeating the same request has the same effect as sending it once?

  3. 3.A client sends invalid data (a negative quantity). Which status code fits?

  4. 4.Why is cursor-based pagination often preferred over page numbers for large, changing data sets?

To complete this lesson

  • ○ Pass the quiz (3/4 correct)