RESTful API Development

Chapter 5
Representations and Interaction Patterns

Bachelors Program in Full Stack Development
RESTful API Development   •   Bachelor

Representations and Interaction Patterns

Introduction

A RESTful API is not merely a collection of URL paths. It is a system through which clients and servers exchange representations of resources and negotiate a shared interaction protocol. A resource such as a customer, invoice, product, or document is an abstract concept; a representation is a transferable description of its current or requested state. JSON is common, but XML, CSV, images, PDF, and other formats may also be appropriate.

Good API design therefore addresses more than serialization. It must answer several questions: Which media type is being exchanged? How does a client discover related resources? How are invalid requests reported? How can a large collection be paginated, filtered, sorted, and searched? How are many changes submitted safely? How are files transferred? How are long-running operations represented without forcing a client to wait?

This chapter develops these interaction patterns and examines their implications for reliability, usability, security, and maintainability.

Learning Objectives

By the end of this chapter, you should be able to:

  • distinguish resources, representations, media types, and hypermedia controls;
  • design useful JSON representations and apply content negotiation;
  • implement links and HATEOAS appropriately;
  • validate requests and produce consistent error responses;
  • design pagination, filtering, sorting, and searching interfaces;
  • evaluate bulk-operation strategies and their failure semantics;
  • design safe file-upload and file-download workflows;
  • model asynchronous operations using status resources and callbacks;
  • identify security, governance, and operational risks in these patterns.

1. Resources, Representations, and Media Types

A resource is an identifiable entity or collection, commonly addressed by a URI. For example:

GET /api/v1/orders/4815

The order is the resource. The bytes returned by the server are a representation of that resource. Two representations of the same order might be JSON for a web application and PDF for a human-readable invoice.

A representation normally contains:

  1. State data: attributes such as an order number, status, and total.
  2. Identity: a stable identifier or URI.
  3. Metadata: information such as timestamps, language, caching directives, or version.
  4. Controls: links or actions that tell a client what it may do next.

The media type describes the format and semantics of the representation. Common examples include application/json, application/xml, text/csv, application/pdf, and image/png. A media type is not simply a file extension: it establishes how the recipient should interpret the bytes.

Content negotiation

HTTP content negotiation separates what the client can accept from what it sends. A client uses Accept to express preferred response types:

GET /api/v1/orders/4815 HTTP/1.1
Host: example.edu
Accept: application/json, application/xml;q=0.8

The server uses Content-Type to identify the response format:

HTTP/1.1 200 OK
Content-Type: application/json

For a request body, Content-Type identifies the submitted representation:

POST /api/v1/orders HTTP/1.1
Content-Type: application/json
Accept: application/json

If the server cannot produce a representation acceptable to the client, 406 Not Acceptable is appropriate. If the server does not support the submitted request format, 415 Unsupported Media Type is appropriate. Servers should document supported media types and should not silently reinterpret an unknown format.

A custom media type can communicate a stable contract and version, for example:

application/vnd.example.order+json;version=2

Versioning through a media type can be elegant, but it increases testing and documentation obligations. Whether versioning appears in the URI, media type, or another mechanism, compatibility rules should be explicit. Additive changes are generally safer than changing the meaning or type of an existing field.

Designing JSON representations

JSON objects should represent domain concepts rather than database tables. A useful representation is consistent, explicit, and sufficiently complete for the intended interaction.

{
  "id": "4815",
  "status": "shipped",
  "currency": "USD",
  "total": 125.50,
  "placedAt": "2025-02-14T10:30:00Z",
  "customer": {
    "id": "c-77",
    "displayName": "Amina Rahman"
  },
  "_links": {
    "self": { "href": "/api/v1/orders/4815" },
    "customer": { "href": "/api/v1/customers/c-77" },
    "invoice": { "href": "/api/v1/orders/4815/invoice" }
  }
}

Important design decisions include:

  • Naming: choose one convention, such as camelCase, and apply it consistently.
  • Nullability: distinguish an absent field, a field with null, and an empty collection when these have different meanings.
  • Dates and times: use an unambiguous standard such as ISO 8601 with an explicit offset or UTC marker.
  • Money: transmit currency and define precision. Floating-point values can introduce rounding problems; integer minor units or decimal types are often safer for financial systems.
  • Identifiers: avoid exposing database implementation details when a stable public identifier is more appropriate.
  • Sparse fields: field selection can reduce payload size, but must not make the default representation confusing or insecure.

A collection response should usually be an object rather than a bare array, because an object can carry pagination metadata and links:

{
  "items": [
    { "id": "4815", "status": "shipped" },
    { "id": "4816", "status": "processing" }
  ],
  "count": 2,
  "_links": {
    "self": { "href": "/api/v1/orders?status=active" },
    "next": { "href": "/api/v1/orders?status=active&page=2" }
  }
}

2. Hypermedia and HATEOAS

Hypermedia as the Engine of Application State, or HATEOAS, means that a server supplies controls that guide the client's next interaction. Rather than requiring the client to hard-code every workflow transition, the client follows links and available actions supplied by the server.

A link commonly contains:

  • href: the target URI;
  • rel: the relationship, such as self, next, cancel, or payment;
  • method: when an action is represented explicitly;
  • type: the expected media type;
  • optional metadata such as title, availability, or parameters.

For example:

{
  "id": "p-100",
  "state": "awaiting_payment",
  "_links": {
    "self": { "href": "/api/v1/payments/p-100", "rel": "self" },
    "pay": {
      "href": "/api/v1/payments/p-100/confirm",
      "rel": "confirm",
      "method": "POST"
    },
    "cancel": {
      "href": "/api/v1/payments/p-100/cancel",
      "rel": "cancel",
      "method": "POST"
    }
  }
}

The presence of pay indicates that payment is currently possible; its absence can indicate that the transition is not available. This is particularly valuable in stateful business workflows. A client should still handle authorization failures and state changes because a link can become invalid between retrieval and use.

HATEOAS is not equivalent to placing URLs in arbitrary fields. Links should have defined relationship semantics, and clients should understand the media type contract. Nor does HATEOAS eliminate documentation. Developers need to know the meaning of representations, link relations, authentication, and error behavior.

A practical adoption strategy is incremental: begin with stable self, collection, pagination, and related-resource links; then add workflow controls where clients benefit from server-driven state transitions.

Hypermedia order workflow pending paid shipped cancelled confirm dispatch cancel The representation exposes only currently valid workflow controls.
Hypermedia order workflow from pending to shipped or cancelled
Figure: Hypermedia order workflow from pending to shipped or cancelled

Figure: A hypermedia representation can expose valid order transitions according to current state.

3. Validation and Error Representations

Validation protects both the domain model and the API contract. It should occur at multiple levels:

  1. Syntax validation: Is the body valid JSON? Are required headers present?
  2. Schema validation: Are fields of the correct type and shape?
  3. Semantic validation: Is a date range valid? Is an amount positive?
  4. Business validation: Is the requested operation allowed for this account and state?

A server should not rely exclusively on client-side validation. The server is the final authority because clients may be old, malicious, or incorrectly implemented.

A consistent error format helps clients respond programmatically. RFC 9457 Problem Details is a widely used model:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
  "type": "https://example.edu/problems/invalid-order",
  "title": "Order validation failed",
  "status": 422,
  "detail": "One or more fields are invalid.",
  "instance": "/api/v1/orders/requests/abc-91",
  "errors": [
    { "field": "items", "code": "required", "message": "At least one item is required." },
    { "field": "currency", "code": "unsupported", "message": "Use USD or EUR." }
  ]
}

Do not expose stack traces, SQL statements, internal paths, or secrets. Error messages should be useful without becoming an information-disclosure channel. The status code communicates a broad category; the problem type and field errors provide actionable detail.

4. Pagination, Filtering, Sorting, and Searching

Collection endpoints must be designed for potentially large and changing data sets. Returning every record creates latency, memory, bandwidth, and denial-of-service risks.

Pagination models

Offset pagination uses parameters such as page and pageSize, or offset and limit:

GET /api/v1/products?page=3&pageSize=25

It is simple and supports direct page navigation, but records inserted or deleted before the current offset can cause duplicates or omissions. Large offsets can also be expensive in some databases.

Cursor pagination returns an opaque cursor representing a position in an ordered result:

GET /api/v1/products?limit=25&after=eyJpZCI6IjEwMDAifQ

The cursor must be treated as an opaque token. Cursor pagination is often more stable and efficient for feeds, but it does not naturally support jumping to page 100. The ordering must be deterministic, usually by a timestamp plus a unique identifier as a tie-breaker.

A response might include:

{
  "items": [],
  "page": {
    "limit": 25,
    "hasMore": true,
    "nextCursor": "opaque-token"
  },
  "_links": {
    "next": { "href": "/api/v1/products?limit=25&after=opaque-token" }
  }
}

The server should enforce maximum page sizes. A requested limit=1000000 should be rejected or capped, with documented behavior.

Filtering, sorting, and search

Filtering narrows records by structured conditions:

GET /api/v1/orders?status=paid&createdAfter=2025-01-01

Sorting should use an allow-list rather than directly concatenating user input into a database query:

GET /api/v1/orders?sort=-createdAt,total

Here - may mean descending order, but the convention must be documented. Search can mean exact field matching, full-text search, or an external search service. These are different capabilities and should not be confused. Search terms should be bounded in length, normalized appropriately, and protected against injection. Query parameters should have defined behavior for unknown fields, invalid values, and conflicting filters.

5. Bulk Operations and Idempotency

Bulk operations improve efficiency when a client must process many resources. They also create complex failure semantics. A request such as POST /orders/bulk-cancel may contain multiple items, each of which can succeed or fail.

Three common policies are:

  • All-or-nothing: the operation commits only if every item succeeds. This requires a transaction boundary that can actually encompass all affected resources.
  • Best effort: valid items succeed and invalid items fail independently. The response must report per-item outcomes.
  • Asynchronous batch: the server accepts a job and processes it later, appropriate for large or long-running batches.

A synchronous result might be:

{
  "results": [
    { "id": "4815", "status": "succeeded" },
    { "id": "4816", "status": "failed", "code": "already_shipped" }
  ]
}

Clients may retry after timeouts, so mutating requests should consider idempotency. An Idempotency-Key allows the server to associate retries with the original operation:

POST /api/v1/payments
Idempotency-Key: 8f4c2c1e-...

The server should store the key, request fingerprint, result, and an expiry policy. Reusing a key with a different request body should be rejected. Idempotency does not mean every operation is naturally safe; it is a mechanism for making repeated submissions produce one logical effect.

6. File Transfer

Files require different concerns from ordinary JSON resources: size, streaming, content type, malware, storage, range requests, and access control.

For downloads, return an accurate Content-Type, a safe Content-Disposition, and preferably an integrity-related header or documented checksum. Large files should be streamed rather than loaded entirely into application memory. HTTP range requests can support resumable downloads when the server provides appropriate validators such as ETag.

For uploads, use multipart form data for a simple API:

POST /api/v1/documents
Content-Type: multipart/form-data; boundary=...

A robust upload policy should:

  • enforce maximum size and count;
  • validate the declared and detected media type;
  • generate a server-side filename;
  • store outside executable web roots;
  • scan for malware where appropriate;
  • authorize access independently of the filename;
  • avoid trusting client-supplied path components;
  • record ownership, retention, and deletion metadata.

For very large objects, a two-step design is common: the API creates an upload session or issues a short-lived pre-signed storage URL; the client transfers the bytes directly to object storage; the API then verifies completion and associates the object with the domain resource. The callback or completion request must be authenticated and must verify size, checksum, and ownership.

7. Asynchronous Workflows

Some operations exceed normal request timeouts: video processing, report generation, bulk imports, and external payment settlement are examples. A server should not keep an HTTP connection open indefinitely merely because work is unfinished.

A common pattern is:

  1. The client submits a request.
  2. The server validates it and returns 202 Accepted.
  3. The response contains a status resource in Location or a link.
  4. The client polls, receives a callback, or subscribes to events.
  5. The status resource eventually reports success or failure.
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/j-902
Retry-After: 5
Content-Type: application/json
{
  "id": "j-902",
  "state": "running",
  "progress": 40,
  "_links": {
    "self": { "href": "/api/v1/jobs/j-902" },
    "cancel": { "href": "/api/v1/jobs/j-902/cancel", "method": "POST" }
  }
}

The state model should define terminal and non-terminal states, retry behavior, expiration, and error details. Progress percentages can be misleading when work is not measurable; an enumerated phase may be more honest. Polling clients should respect Retry-After, use exponential backoff where appropriate, and stop after a documented terminal state or expiry.

Webhooks reduce polling but introduce delivery concerns. Events should include an identifier, timestamp, event type, and resource reference. Consumers should verify signatures, tolerate duplicates, process events idempotently, and handle out-of-order delivery. A webhook endpoint must not assume that a request is trustworthy merely because it arrives from a known network address.

8. Worked Design Example

Consider a university library API that allows students to search books, reserve available copies, upload research documents, and request a generated citation package.

A search request could be:

GET /api/v1/books?q=distributed+systems&subject=computing&limit=20

The response includes book data, a cursor, and links. Each book exposes reserve only when the authenticated student is eligible and a reservable copy exists. This avoids requiring the client to reconstruct all policy rules.

A reservation request uses an idempotency key:

POST /api/v1/books/b-44/reservations
Idempotency-Key: student-77-20250214-001

If citation generation is lengthy, the server returns a job resource. The student interface can poll the job or receive a signed webhook. Uploaded documents are scanned, stored under generated names, and represented by metadata rather than exposing raw storage paths.

The design separates concerns: search is a read-oriented collection interaction; reservation is a state transition; document upload is a controlled file transfer; citation generation is an asynchronous workflow. Each operation has a representation suited to its purpose.

9. Applied Case: Illustrative Online Retail Platform

Background

An illustrative retailer has a mobile application, a partner marketplace, and an internal fulfillment system. The original API returns unbounded arrays of orders, uses different error formats for each team, and requires clients to guess when an order can be cancelled.

Problem

Mobile clients experience slow responses, partners cannot reliably retry payment requests, and integration defects occur when order states change. Large CSV exports also time out.

Analysis

The platform needs bounded collections, stable representations, explicit state transitions, and asynchronous processing. It must also preserve compatibility with existing clients.

Approach

The team introduces cursor pagination with a maximum limit, a documented JSON media type, and Problem Details errors. Order representations expose self, invoice, and conditionally available cancel links. Payment creation accepts an idempotency key. CSV export returns a job resource, while the completed file is available through a short-lived authorized download link.

The team also adds observability: request identifiers, structured logs, latency metrics, job duration, validation-failure counts, and audit records for cancellation and download events.

Outcome

Clients no longer download unbounded collections, retries do not create duplicate payments, and workflow behavior is driven by explicit server controls. Export requests return quickly, although the organization must continue managing job retention, storage costs, and webhook reliability.

Learning points

The case demonstrates that representations are part of system behavior, not cosmetic formatting. Pagination controls resource consumption; hypermedia communicates allowed transitions; idempotency handles unreliable networks; and asynchronous resources separate acceptance of work from completion of work.

10. Governance, Security, and Professional Practice

Representation design has governance consequences. APIs may expose personal data, financial information, educational records, or confidential documents. Data minimization should guide both default fields and links. Authorization must be checked for the resource and every related representation or action; hiding a link is not a substitute for authorization.

Important controls include:

  • TLS for data in transit;
  • authentication and fine-grained authorization;
  • rate limits and maximum payload sizes;
  • protection against injection, mass assignment, and denial-of-service attacks;
  • audit logs for sensitive actions;
  • retention and deletion policies;
  • redaction of secrets and personal data in logs;
  • schema and contract testing across versions.

AI-assisted code generation can accelerate serializers, schemas, and test scaffolding, but generated code must be reviewed. Developers should not paste production secrets or personal data into external tools. AI output may omit authorization checks, mishandle file validation, or produce incompatible schemas. Human review, threat modeling, and automated tests remain essential.

Best-Practice Checklist

  • Define representations independently of persistence schemas.
  • Use explicit media types and honest content negotiation.
  • Keep naming, nullability, timestamps, and error formats consistent.
  • Provide meaningful links for identity, navigation, and workflow transitions.
  • Validate syntax, schema, semantics, and business rules on the server.
  • Bound collection responses and document pagination stability.
  • Allow-list filter and sort fields.
  • Design retries and idempotency before production failures occur.
  • Stream large files and apply independent file-security controls.
  • Represent long-running work as a status resource.
  • Version deliberately and test backward compatibility.
  • Treat authorization, privacy, observability, and retention as part of API design.

Chapter Summary

Representations are transferable descriptions of resources, while media types define how those descriptions are interpreted. JSON is common but should be selected and structured according to the interaction rather than database convenience. Content negotiation uses Accept and Content-Type to establish format expectations.

Hypermedia and HATEOAS add navigational and workflow controls to representations. Validation should address syntax, schema, semantics, and business rules, with consistent Problem Details errors. Collection endpoints require bounded pagination, carefully defined filtering, allow-listed sorting, and an explicit distinction between structured filtering and full-text search.

Bulk operations must define all-or-nothing, partial-success, or asynchronous behavior. Idempotency keys make retried mutations safer. File transfer requires streaming, type and size validation, malware controls, safe storage, and authorization. Long-running work should be modeled with 202 Accepted and a status resource, optionally supplemented by secure, duplicate-tolerant webhooks.

Professional API design integrates usability with security, privacy, governance, observability, and compatibility. The central principle is to make valid interactions clear, bounded, discoverable, and safe to repeat.

Key Terms

Resource: An identifiable conceptual entity or collection addressed by a URI.

Representation: A transferable description of a resource’s state.

Media type: A standard label describing the format and semantics of exchanged content.

Content negotiation: The process by which client and server agree on a representation format.

HATEOAS: Hypermedia as the Engine of Application State; an approach using server-provided controls to guide interaction.

Link relation: The semantic relationship between a link and its context, such as self, next, or cancel.

Schema validation: Checking whether data has the required structure and types.

Semantic validation: Checking whether values make sense in context.

Problem Details: A standardized structure for communicating machine-readable HTTP errors.

Pagination: Dividing a large collection into bounded responses.

Offset pagination: Pagination based on numeric positions or page numbers.

Cursor pagination: Pagination based on an opaque position token.

Filtering: Selecting records using structured criteria.

Sorting: Ordering records according to permitted fields and directions.

Idempotency: A property whereby repeating a request has one intended logical effect.

Bulk operation: An operation that processes multiple items in one interaction.

Multipart upload: A request format that transfers files and fields as separate parts.

Asynchronous workflow: Processing in which acceptance and completion occur in separate interactions.

Webhook: A server-initiated HTTP notification about an event.

Content-Type: The header identifying the media type of a request or response body.

Review Questions

Short Answer Questions

  1. Distinguish a resource from its representation.
  2. What roles do the Accept and Content-Type headers play?
  3. Why should collection responses usually be bounded?
  4. State two security controls required for file uploads.
  5. What is the purpose of an idempotency key?

Long Answer Questions

  1. Explain HATEOAS and evaluate its benefits and limitations in a client application.
  2. Compare offset pagination and cursor pagination, including their stability and usability trade-offs.
  3. Design a consistent validation and error-reporting strategy for a RESTful API.
  4. Explain how an API should model a long-running report-generation operation.
  5. Discuss the representation, security, and governance issues involved in API versioning.

Analytical / Application Questions

  1. Design the request and response interaction for a bulk order-cancellation endpoint that permits partial success. Define its status codes, result format, and retry behavior.
  2. An API returns duplicate records when clients move through pages during periods of frequent insertion. Diagnose the likely cause and propose a more stable pagination design.
  3. Design an end-to-end workflow for uploading a 2 GB video, scanning it, and generating a downloadable transcript asynchronously. Identify the security and failure controls required.

Multiple Choice Questions with Answers

Question 1

Which header communicates the representation formats a client can receive?

A. Accept

B. Content-Length

C. Authorization

D. Location

Correct Answer: A. Accept

Question 2

What does HATEOAS primarily add to a representation?

A. Database indexes

B. Workflow and navigation controls

C. Encryption keys

D. Server-side threads

Correct Answer: B. Workflow and navigation controls

Question 3

Which HTTP status is appropriate when the submitted media type is unsupported?

A. 201

B. 404

C. 415

D. 500

Correct Answer: C. 415

Question 4

Which pagination method generally provides a stable position for continuously changing feeds?

A. Cursor pagination

B. Random pagination

C. Unbounded pagination

D. Header-only pagination

Correct Answer: A. Cursor pagination

Question 5

What is the main purpose of an idempotency key on a payment request?

A. To compress the response

B. To prevent a retry from creating an additional logical payment

C. To select the response language

D. To encrypt the payment amount

Correct Answer: B. To prevent a retry from creating an additional logical payment

Question 6

Which response pattern is most appropriate for accepted work that will finish later?

A. 202 Accepted with a status resource

B. 204 No Content with no tracking mechanism

C. 301 Moved Permanently

D. 304 Not Modified

Correct Answer: A. 202 Accepted with a status resource

Question 7

Why should sort fields normally be allow-listed?

A. To increase image resolution

B. To prevent arbitrary query construction and define supported behavior

C. To remove authentication requirements

D. To force XML responses

Correct Answer: B. To prevent arbitrary query construction and define supported behavior

Question 8

Which practice is safest for uploaded filenames?

A. Use the client filename as a storage path

B. Permit directory traversal characters

C. Generate a server-side filename and validate the content

D. Execute files to identify their type

Correct Answer: C. Generate a server-side filename and validate the content

Question 9

What does the Content-Type response header identify?

A. The response body’s media type

B. The user’s password

C. The database transaction ID

D. The pagination cursor only

Correct Answer: A. The response body’s media type

Question 10

Which statement about webhooks is correct?

A. They never need authentication

B. Consumers should tolerate duplicate delivery

C. They guarantee ordered delivery in all systems

D. They eliminate authorization checks

Correct Answer: B. Consumers should tolerate duplicate delivery

RESTful API Development
Chapter 5 of 15