Richardson REST Maturity Model
Back to Learn
FAACChapter 11

Corporate API Fundamentals and Architecture

Richardson REST Maturity Model

From a single endpoint to hypermedia: how to assess, evolve, and govern HTTP APIs without confusing adoption levels with complete architectural compliance

In-depth edition - study material and professional reference

Four-stage evolution of the Richardson REST Maturity Model, from a single endpoint to hypermedia

Interface evolution according to the

Evolution of the interface through the four levels of the Richardson Maturity Model
Overview - Single , capabilities, , and form a cumulative progression of observable capabilities.

Each level adds a drawing ability; the model does not certify complete compliance with REST.

Chapter presentation

The , commonly abbreviated as , organizes service interfaces into four levels: a message-oriented entry point, identifiable resources, semantic use of HTTP, and controls. The model was proposed by Leonard Richardson and popularized by Martin Fowler as a didactic way to decompose some central elements of a REST approach. Its value is in allowing teams to look at concrete capabilities of the interface without relying solely on the “RESTful” label.

The model, however, is not a certification standard and does not replace the architectural constraints described by Roy Fielding. An API can reach level 2 by using HTTP resources, methods, and code consistently and still maintain a conversational session on the server, prevent caching, expose implementation details, or create strong temporal coupling. Likewise, an interface can adopt links without its clients actually navigating through the transitions offered. Therefore, level and quality are not automatic synonyms.

In this chapter, each level will be analyzed in depth, with examples of fictional corporate and banking APIs. The effects on contracts, consumers, API Gateways, retries, , caching, authorization, observability and evolution will be studied. The objective is not to advocate that every API must reach level 3, but to provide criteria for consciously choosing how far to advance and what properties to obtain.

The analysis will also show that cross-tier migration is not just an exchange of URLs. It requires identifying resources, separating commands from representations, assigning correct semantics to methods and responses, defining relationships, planning for compatibility, and adjusting gateway policies. In environments with many consumers, the evolution sequence needs to be measurable and reversible.

How to Study This Chapter Use the same business operation when going through all levels. Compare the way of addressing, the intention expressed by the method, the codes returned, the possibility of caching, the retry rules and the knowledge required from the client. Comparison better reveals what each level adds.

Learning Objectives

  • Explain the origin, purpose and limits of the .
  • Differentiate levels 0, 1, 2 and 3 by observable properties of the interface.
  • Recognize RPC patterns and imperative messages concentrated on an .
  • Model stable resources without confusing , table, DTO and operation.
  • Apply HTTP methods, codes, headers, cache and preconditions at level 2.
  • Design links and actions that represent permitted transitions.
  • Compare with REST architectural constraints and with OpenAPI.
  • Evaluate existing APIs without turning the analysis into a superficial score.
  • Plan incremental migration, governance and troubleshooting on API Gateways.

Chapter structure

  • 11.1 Origin and purpose of the model
  • 11.2 What measures - and what it doesn't measure
  • 11.3 Overview of the four levels
  • 11.4 Level 0: The Swamp
  • 11.5 Level 0 operational standards and risks
  • 11.6 Transition from level 0 to level 1
  • 11.7 Level 1: Resources
  • 11.8 Identity, granularity and lifecycle
  • 11.9 Level 1 Limitations
  • 11.10 Transition to level 2
  • 11.11 Level 2: HTTP methods and semantics
  • 11.12 Status, headers, cache and preconditions
  • 11.13 , retries and errors
  • 11.14 Level 2 in API Gateways
  • 11.15 Level 3: Controls
  • 11.16 Relationships, links and actions
  • 11.17 Types of media and contracts
  • 11.18 Transition-driven clients
  • 11.19 Benefits, costs and pitfalls of level 3
  • 11.20 versus Fielding's REST
  • 11.21 , OpenAPI and governance
  • 11.22 Evaluation matrix
  • 11.23 Migration strategy
  • 11.24 Observability and troubleshooting
  • 11.25 Case studies and labs
  • Summary, checklist, exercises, glossary and references

11.1 Origin and purpose of the model

Leonard Richardson formulated the model as a way to classify web service styles by the progressive adoption of web features. Martin Fowler popularized it in 2010 with the image of a ladder: at level 0 there is a single message-oriented entry point; at level 1 resources appear; at level 2 the interface uses HTTP methods and responses; at level 3 the representations offer controls. The simplicity of this decomposition has made useful in training, architecture reviews, and modernization discussions.

The word maturity can lead to a misinterpretation. Higher level does not necessarily mean that the product, team, or domain is “more mature” in every aspect. The model describes a specific dimension of the interface. Security, availability, governance, documentation, performance, privacy, consistency and developer experience need their own assessments. A Level 2 API can be highly reliable and context-appropriate; a level 3 API may be insecure or poorly operated.

The model works best as a diagnostic language. Instead of just asking “is this API REST?”, the team can ask: are there identifiable resources? Do methods express intent? Does the response use coherent statuses and headers? Does the consumer discover transitions through ? These questions produce evolving evidence and decisions.

Responsible use of the term maturity Use the level to describe interface capabilities, not to classify people or determine total quality. Separately record attributes such as security, compatibility, SLOs, documentation, governance and operational cost.

11.2 What measures - and what it doesn't measure

mainly observes three moves: decomposing a generic operation into identifiable resources, taking advantage of HTTP's standardized semantics, and making transitions visible in the itself. These moves reduce some of the coupling between consumer and server because they transfer knowledge to shared Web elements: URIs, methods, codes, headers, links and relations.

The model does not check all REST constraints. Client-server, stateless, cache, layered system and code on demand do not appear as independent steps. Level 2 touches on caching and uniform interface, and Level 3 approaches as an application state driver, but full evaluation of REST requires broader architectural analysis. Therefore, Fowler describes level 3 as a step toward “REST glory,” not automatic proof of compliance.

There is also no universal test to decide the level when the API mixes styles. A platform may have query endpoints at level 2, legacy commands at level 0 and a specific flow with . In these cases, classifying the entire API by a single number hides information. The analysis must be done by surface, or business journey, recording exceptions.

11.3 Overview of the four levels

The four cumulative levels of the Richardson Maturity Model
Figure 1 - organizes interface capabilities into four cumulative levels, but does not measure all attributes of an API platform.
Table 1 - Capabilities, dependencies and risks associated with each level.
LevelAdded elementCore client knowledgeCharacteristic risk
0Messages about an endpointOperations and proprietary formatCentral dispatcher, little shared semantics
1Resources and identifiersWhat resources exist and how to address themResources treated only as command envelopes
2HTTP methods, status and headersProtocol semantics and resource contractDecorative use of inconsistent verbs or codes
3Hypermedia ControlsMedia relationships and typesLinks without semantics or clients that continue to encode the flow

11.4 Level 0: The Swamp

At level 0, the service typically publishes a single and uses the message body to indicate which operation should be performed. stands for “Plain Old XML”, a historical expression for XML messages without taking advantage of richer Web resources; In current practice, the same structure may appear with JSON, Protobuf, or another format. The decisive aspect is not the format, but the concentration of intentions in a generic interface.

A payments service could always receive POST /service-payments and distinguish operations by a field like operation. Check balance, create transfer, cancel appointment and issue statement share the same address and method. The server acts as a dispatcher: it interprets the command and forwards it to the corresponding routine. Many SOAP services, RPC over HTTP, and legacy integrations approach this level.

Multiple intents converging on an endpoint and dispatcher at level 0
Figure 2 - At level 0, the protocol carries a proprietary message and the body concentrates the intention of the operation.

Conceptual example of a message at level 0

POST /payment-service HTTP/1.1
Content-Type: application/json
{
  "operation": "CREATE_TRANSFER",
  "sourceAccount": "991",
  "destinationAccount": "552",
  "amount": 120.00
}

Level 0 is not synonymous with bad implementation. In closed scenarios, command queues, binary protocols, highly specialized operations, or compatibility with legacy systems, RPC may be a valid decision. The problem arises when the organization expects Web properties - caching, uniform semantics, visibility through intermediaries and decoupled evolution - without exposing elements that allow them to be obtained.

11.5 Level 0 operational standards and risks

The main consequence is that intermediate components see little difference between operations. An API Gateway observes multiple POSTs for the same path, and the real distinction is hidden in the body. Authorization rules, quotas, caching, metrics, and routing need to inspect content or trust proprietary fields. This increases policy costs, reduces performance and makes it difficult to correlate with tools that aggregate metrics by method and route.

Retries also become risky. The POST method does not tell you whether an operation is repeatable, and the same can contain queries, idempotent commands, and non-idempotent commands. A timeout leaves the client without knowing whether the server performed the action. The solution often requires correlation identifiers, keys, or processing status, but these mechanisms need to be defined outside the basic semantics of the protocol.

Errors often return 200 with an envelope containing success=false or internal codes. This practice prevents load balancers, gateways, SDKs, and observability from using the HTTP status class as a signal. It also creates ambiguity between transport failure, gateway rejection and business error. The consumer needs to interpret the body before classifying any result.

Level 0 Signal If the documentation starts with a list of accepted operations in an action, command, operation, or serviceName field and almost everything uses POST in the same path, the interface is probably at level 0, even when the messages are JSON and the product is called a REST API.

Table 2 - Typical effects of an interface concentrated at level 0.
SymptomImpact on the gatewayImpact on the consumer
One URI for everythingPolicies depend on body inspectionSDK needs to know dispatcher and internal codes
200 for success and errorStatus metrics become misleadingError handling depends on the envelope
POST for reading and writingCache and security cannot infer intentRetry requires specific rule per operation
Extensive core contractChanges affect large surfaceVersioning and testing become monolithic

11.6 Transition from level 0 to level 1

The first transition consists of making explicit the entities or concepts that have an identity and life cycle. Instead of sending all messages to /service, the interface now addresses customers, accounts, transfers, appointments and statements. This change requires understanding the domain: a transfer is not just a function; it can be created, validated, confirmed, rejected, canceled and consulted over time.

The migration must start with inventory. Each dispatcher operation is classified as query, create, change, command, process, or integration. Next, the team identifies which objects need a stable address, which are subordinate to others, and which represent processes. The goal is not to turn every table into an , but to find units of meaning that consumers can reference.

Compatibility can be preserved with an adaptation layer. The legacy continues to accept messages and internally calls the new -oriented services. New consumers adopt the new surface, while metrics measure the reduction in use of the old contract. This strategy avoids a “big bang” migration and allows you to validate the modeling before removing the dispatcher.

Modeling Question What needs to be identified, queried, or referenced after the operation is complete? The answer often reveals a . A transfer request, for example, continues to exist as an auditable entity even after the initial response.

11.7 Level 1: Resources

At level 1, the interface publishes multiple resources with their own identifiers. The consumer no longer knows just a generic gateway and starts interacting with addresses that represent parts of the domain. The URI serves as an identifier, not as a complete description of the implementation. /transfers/abc can remain valid even if the service changes bank, language or topology.

The model does not require level 1 to correctly use all HTTP methods. The API can continue sending POST to /customers/483/view, /transfers/abc/cancel or /accounts/991/statement. There has been progress in identification, but the intention is still partially encoded in path verbs or in the body. This characteristic explains why resources are necessary but insufficient for a semantically rich HTTP interface.

Distinct resources with identity and scope visible at level 1
Figure 3 - Distinctive capabilities make identity and scope visible, although operations may still remain imperative.

11.8 Identity, granularity and lifecycle

A is an identifiable abstraction, not necessarily a database row. It can represent a durable entity, a collection, a projection, a document, a process, or the result of a calculation. /limits-operacional/customer-483 may be a calculated view; /transfer-requests/abc can represent a process; /statements/account-991/2026-07 can represent a document produced for a period.

Granularity should reflect cohesion and access patterns. Excessively large resources force consumers to transfer and update irrelevant data. Very fragmented resources increase round trips and composition complexity. In corporate systems, the boundary also needs to consider authorization, ownership, transactional consistency and capacity for independent evolution.

Public identifiers should not expose internal keys unnecessarily. A sequential number can facilitate enumeration and reveal volume; a table key can change during migrations. The API can use opaque identifiers, business aliases, or stable URIs. The important thing is to define uniqueness, scope, permanence and behavior when the is removed or replaced.

Table 3 - Questions to model resources at level 1.
DecisionTechnical questionExample
IdentityDoes the resource need to be referenced later?/transferences/{id}
ScopeIs identity global or subordinate?/accounts/{account}/schedules/{id}
GranularityWhat data changes and is authorized together?separate registration preferences
Life cycleWhat states and transitions are there?PENDING -> CONFIRMED -> SETTLED
PermanenceDoes the identifier survive internal migrations?opaque public ID

11.9 Level 1 Limitations

Separating resources improves observability and organization, but does not alone resolve the semantics of operations. Endpoints such as POST /transfers/abc/view and POST /transfers/abc/remove still hide properties known by HTTP. The gateway cannot infer that querying is safe or that removing should produce a certain response class. The client depends on conventions specific to each API.

Another risk is creating “fake resources” just to accommodate verbs. Paths such as /createTransfer, /executePayment or /getCustomers use multiple addresses, but continue modeling functions. This interface may be clear and functional, but progress toward a uniform interface is limited. Analysis should look at the meaning of the identifier, not just count URLs.

At level 1, collections and relationships can also be inconsistent. One team can use /customer/483/account and another /viewContasPorCliente?id=483. Without standards for naming, cardinality, pagination, and errors, expansion increases surface area without generating predictability. Governance remains necessary.

11.10 Transition to level 2

The second transition is to map intentions to . Queries use GET or HEAD; creation usually uses POST in the collection; idempotent substitution can use PUT; removal uses DELETE; Partial updates can use PATCH when their format and semantics are defined. The method stops being just a transport field and starts communicating properties to clients and intermediaries.

This migration also requires reviewing responses. Creation may return 201 Created with Location; asynchronous processing can use 202 Accepted; unsatisfied precondition may produce 412; state conflict may produce 409; validation can use . Headers such as ETag, Cache-Control, Allow, Retry-After and Vary become part of the contract.

It is not enough to replace POST with different verbs. Behavior needs to respect security, and semantics. A GET that cancels a schedule is still dangerous, even if the path appears -oriented. A PUT that creates additional effects on each repetition is not idempotent. Level 2 relies on observable behavior, not syntactic decoration.

Example of reading with

GET /transfers/abc HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
ETag: "v7"
{ "id": "abc", "status": "PENDING", "amount": 120.00 }

Transition criteria For each operation, record: target , method, security property, , success response, errors, headers, cacheability, and retry policy. The table highlights where changing the verb requires a real change in behavior.

11.11 Level 2: HTTP methods and semantics

At level 2, the interface uses the HTTP vocabulary to express intentions. The semantics are shared across browsers, libraries, proxies, gateways, and observability tools. GET is safe and should not request a change of state; PUT and DELETE are idempotent; POST is flexible and normally non-idempotent; HEAD has the same semantics as GET without response content. PATCH depends on the type of patch document used.

The benefit is not just aesthetic. A gateway can apply different rules for reading and writing, caches can reuse responses, SDKs can classify results by status, clients can implement retries of idempotent operations more safely, and SRE teams can group metrics by method and route. The interface becomes more visible to components that do not know the domain.

HTTP methods and responses carrying shared semantics at level 2
Figure 4 - Standardized methods and responses allow generic components to understand interaction properties.

11.12 Status, headers, cache and preconditions

Status codes classify the result of attempting to process the request. They do not replace domain details, but provide an interoperable first layer. 2xx indicates successful processing; 3xx advises redirection or reuse; 4xx indicates that the request cannot be met under the conditions presented; 5xx points to a server or intermediary failure. The choice should reflect who produced the response and the observed state.

Headers expand semantics. Location identifies the created or the relevant location; ETag represents a version of the ; If-Match and If-None-Match express preconditions; Cache-Control controls reuse; Retry-After guides retry; Allow reports supported methods; Vary describes which fields in the request influence the response. Ignoring these elements reduces level 2 to a table of verbs.

Preconditions are especially important in enterprise APIs. Two consumers can read the v7 version of a and attempt to update it. Without control, the last writing overwrites the previous one. With ETag and If-Match, the server performs the change only if the version still matches. If the state has changed, it returns 412 Precondition Failed, allowing the client to reload and reconcile.

Precondition protected update

PUT /preferences/customer-483 HTTP/1.1
Content-Type: application/json
If-Match: "v7"
{ "language": "pt-BR", "notifications": true }
HTTP/1.1 412 Precondition Failed
Content-Type: application/problem+json
Table 4 - Protocol elements that make the interface more operable.
HTTP ElementUse at level 2Common fault
201 + LocationConfirm creation and inform identifierReturn 200 without reference to new resource
202 + monitorAccept process not yet completedTreating acceptance as ultimate success
ETag/If-MatchPrevents lost updatesGenerate ETag without validating preconditions
Cache-ControlDefines reuse and revalidationCache sensitive response without explicit policy
Retry-AfterGuide new attemptReply 429/503 without window or strategy

11.13 , retries and errors

means that repeating the same request produces the same intended effect on the server, although the of the response may vary. PUT and DELETE are defined as idempotent; POST does not receive this guarantee by default. In distributed systems, timeout does not prove that the operation failed. The client may lose the response after the server completes the command, creating a risk of duplication.

For non-idempotent operations, an key can associate equivalent attempts with a single result. The server needs to define scope, expiration, payload comparison, persistence and concurrent behavior. The gateway may require the header and limit format, but business deduplication generally belongs to the service that knows the operation and its transaction.

Errors must combine HTTP status and a stable . , currently defined by RFC 9457, provides fields such as type, title, status, detail and instance, as well as extensions. The status classifies the result; the type identifies a problem category; extensions carry structured data. Internal messages, stack traces and sensitive data must not be exposed.

Structured error at level 2

HTTP/1.1 409 Conflict
Content-Type: application/problem+json
{
  "type": "https://api.example/problems/invalid-state",
  "title": "Transition not allowed",
  "status": 409,
  "detail": "The transfer has already been settled.",
  "instance": "/transfers/abc"
}

Retry is not just client configuration The strategy depends on method, , failure phase and deduplication capability. Automatically repeating a financial POST after timeout without an key can duplicate effects.

11.14 Level 2 in API Gateways

API Gateways benefit directly from level 2 semantics. Policies can separate reading and writing per method, apply quotas per operation, block unpublished methods, validate Content-Type and Accept, propagate correlation IDs, produce 405 when the method is not allowed, and normalize infrastructure errors. Metrics by route template and status become more representative.

The gateway, however, does not transform an API into level 2 just by rewriting paths or methods. If it receives GET and internally calls a command that changes state, the security property has been violated. If you convert every backend error into 200, you destroy semantics. If you add ETag without ensuring that the version represents the state, you create a false precondition. Responsibility needs to be shared with the service.

In multi-hop architectures, you must record where each response was created. A 429 can come from the quota gateway, a 503 from the balancer, a 409 from the domain, and a 401 from the identity provider. Standardization helps the consumer, but logs and correlation headers need to preserve the source for troubleshooting.

API Gateway enforcing policies without overriding domain semantics
Figure 5 - The gateway reinforces the interface and applies cross-cutting policies; the domain semantics still belong to the API.
Table 5 - Use of level 2 in gateway policies.
PoliticsAdequate responsibilityAntipattern
AuthenticationValidate credential and contextInvent thin authorization without domain data
RoutingMap contract to upstreamMask incompatible routes without observability
Rate limitingProtect capacity and plansUse the same limit for light read and expensive command
ValidationReject invalid form of contractAccept payload and silently change meaning
Error transformationNormalize infrastructure and formatConvert all errors to 200 or 500

11.15 Level 3: Controls

Level 3 adds controls to representations. In addition to returning data, the server reports relationships and transitions available in the current state. A pending transfer may offer self, confirm, and cancel links; a settled transfer can only offer self and receipt. The client does not need to construct all the URLs or maintain a complete table of states to know which actions are enabled.

This approach is related to the principle: as the engine of application state. “Application state” refers to the client's progress through a sequence of interactions, guided by incoming controls. The server continues to control the state of resources, while the describes possible paths. The Web works this way when a browser receives links and forms.

Hypermedia controls exposing allowed transitions for a transfer
Figure 6 - The of a pending transfer exposes only the transitions allowed at that time.

Conceptual with controls

{
  "id": "abc",
  "status": "PENDING",
  "amount": 120.00,
  "_links": {
    "self":    { "href": "/transfers/abc" },
    "confirm": { "href": "/transfers/abc/confirmation", "method": "POST" },
    "cancel":  { "href": "/transfers/abc/cancellation", "method": "POST" }
  }
}

A useful link has a destination and a semantic relationship. The self relation indicates the canonical identification of the ; next and prev can navigate pages; collection points to the collection; item relates collection and member. Relationships registered with IANA allow shared meaning, while specific relationships can use their own URIs. The field name alone should not be the only semantic definition.

Actions require more information than a href. The client may need method, content type, fields, constraints and documentation. Different formats represent this information in different ways. There is no single mandatory format for REST; the contract must define the type of media, the relationships and how to interpret controls.

Controls need to reflect authorization and status, but their absence does not replace enforcement. The server must validate every action again. A client can fabricate a request or reuse an old link. guides the experience and reduces invalid attempts; authorization and validation remain mandatory.

Table 6 - Relationships must have stable and documented meaning.
RelationshipPossible meaningNote
selfCurrent representation identifierHelp caching, correlation and updating
collectionCollection the item belongs toCan guide navigation and creation
next/prevPagination or sequencePrefer full links to cursor reconstruction
confirmSpecific domain transitionDefine relationship by URI or media contract
describedbyDocument describing the resourceDoes not replace executable controls

11.17 Types of media and contracts

depends on a convention that the client understands. application/json, alone, only defines the JSON syntax; it does not tell you that _links contain relationships, that actions describe forms or how URI templates should be expanded. The API can adopt a known media type, profile, or organization-specific type. The important thing is that the meaning is explicit and versionable.

Specific media types can enable independent evolution of URLs, but also increase governance and tooling. SDKs, validators, gateways, and documentation need to know the format. In organizations with many teams, an internal specification must define mandatory fields, registered relationships, templates, actions, errors, compatibility and security rules.

Web Linking, defined by RFC 8288, allows you to transport links in headers and representations. URI Templates, defined by RFC 6570, allow describing parameterized destinations. These patterns can compose a solution, but they do not alone provide a complete model of actions. The choice must consider consumers’ real capabilities.

JSON does not have by default A field called links is just data until the contract defines relationships, targets, cardinality, templates, and client behavior. The maturity is in the shared semantics, not the object name.

11.18 Transition-driven clients

A -driven client starts with a small set of known points and navigates through relationships. It looks for rel=confirm, instead of concatenating /confirmation; interprets an available action, rather than coding that PENDING always allows confirmation. This reduces coupling to the topology and part of the flow rules.

The reduction is not absolute. The client still knows relationships, media types, and domain semantics. Changing the meaning of confirm is breaking change. Removing a relationship may change functionality. shifts the coupling of URLs and rigid sequences to vocabularies and affordances, which need governance.

Clients generated exclusively from OpenAPI tend to call static operations. To explore level 3, the runtime needs to analyze representations and choose transitions. It is possible to combine the approaches: OpenAPI describes operations and schemas, while relationships in the responses guide availability and navigation. Tests must verify both.

Relationship-driven client pseudocode

transfer = GET(entrypoint).follow("transfer-by-id", id="abc")
if transfer.has_relation("confirm"):
    result = transfer.follow("confirm", body={"otp": "..."})
else:
    show_message("Confirmation is not available in the current state")

11.19 Benefits, costs and pitfalls of level 3

The main benefit is that it allows the server to communicate valid transitions and change certain destinations without requiring clients to reconstruct URLs. This can improve discoverability, reduce invalid calls, facilitate long streams, and make state more explicit. In domains with relevant state machines - onboarding, payments, orders, approvals - dynamic controls can bring concrete value.

The cost appears in design, documentation, libraries and testing. The team needs to define relationship vocabularies, represent actions, maintain media types and educate consumers. Enterprise tools are more mature for OpenAPI and static SDKs than for generic clients. If consumers ignore links and continue concatenating paths, the cost is paid without getting the benefit.

A common pitfall is to return all possible links, regardless of status or authorization. This turns into a static catalog and can expose unnecessary information. Another is to use undefined relations, such as action1 or execute. It is also inappropriate to believe that links eliminate versioning: schemas, relationships and semantics continue to evolve.

Table 7 - The decision to adopt hypermedia depends on the domain and ecosystem.
SituationLevel 3 tends to helpLevel 3 may not pay off
Business flowMultiple states and dynamic transitionsSimple and stable CRUD
ConsumersClients capable of interpreting relationshipsStrict batch integrations and generated SDKs
TopologyDestinies and actions evolve frequentlyFew operations and stable URLs
GovernanceShared vocabulary and media typeEach team invents its own format
OperationTelemetry of relationships and transitionsLinks are not observed or tested

11.20 versus Fielding's REST

The is a didactic decomposition of some elements; REST is an architectural style made up of constraints. Level 1 relates to identification. Level 2 comes closest to uniform interface and the use of . Level 3 emphasizes controls. However, the model does not have explicit steps for client-server, stateless, cache, layered system and code on demand.

An API can be at level 3 and still rely on session affinity in an instance, disable caching on all responses, expose persistence details, and require simultaneous coordination between client and server with each change. In this situation, the interface uses , but the architecture does not achieve several expected REST properties.

The reverse also requires nuance. An API at level 2 can apply client-server, stateless, cache and layers in a robust way, remaining far from the full use of . Calling it “immature” without considering context may be less useful than recording exactly what constraints and properties are present.

Table 8 - RMM and REST answer related but different questions.
AppearanceRichardson Maturity ModelFielding REST
PurposeClassify visible interface capabilitiesDefine architectural style and emergent properties
StructureFour cumulative levelsCombined Constraint Set
FocusResources, HTTP and hypermediaComponents, connectors, data, and constraints
ResultEvaluation and evolution languageAnalysis of architectural properties
LimitDoes not measure total quality or all constraintsDoes not prescribe a single endpoint design

11.21 , OpenAPI and governance

OpenAPI describes HTTP operations, parameters, schemas, responses and security mechanisms. It is excellent for contract design, documentation, client generation, mocking, and testing. However, a valid description can represent any level: a single POST with operation field, multiple resources still handled by POST, a level 2 interface, or operations whose responses include .

Governance can use automatic rules to detect signs of levels: excessive concentration of POST, verbs in paths, lack of 4xx responses, creation without Location, methods incompatible with security, lack of error schemas and operations without tags. These rules are heuristics. The actual semantics, idempotent behavior, and quality of relationships require human review and testing.

In enterprise pipelines, analysis should combine contract lint, contract testing, behavior testing, and telemetry. OpenAPI reports what has been declared; tests verify what the runtime executes; the gateway shows how consumers actually use the interface. An API can document PUT and implement non-idempotent effect; only behavior reveals the divergence.

Contract is not behavior OpenAPI can declare correct methods and responses while the implementation returns 200 for all errors or changes state on GET. Maturity needs to be verified by operational testing and evidence.

11.22 Evaluation matrix

A useful review avoids reducing the interface to a grade. For each journey, record evidence, impact, and recommended action. The level can be informed, but must be accompanied by observations about REST, security and operation. The following table provides minimum questions that can be applied to an API or set of endpoints.

The team must also consider weight and context. The absence of can have low impact on an internal API with two stable consumers, while non-idempotent POST without deduplication can pose critical risk. Priority for improvement should be determined by risk and value, not just distance to level 3.

Table 9 - Evidence-based assessment matrix.
DimensionEvidence questionClue
EndpointDo intents converge on a single generic URI?Level 0
ResourcesDo entities and processes have a stable identity?Level 1
MethodsDo GET, POST, PUT, PATCH and DELETE respect semantics?Level 2
ResponsesStatuses and headers allow generic interpretation?Level 2
HypermediaDo representations expose current relationships and transitions?Level 3
StatelessDoes the request depend on a previous local session?REST Constraint
CacheDo reusable responses have explicit policy?REST Constraint
LayersDoes the client depend on the internal topology?REST Constraint
OperationDo logs distinguish gateway, API and domain?Operational quality

Assessment Conclusion Example

Journey: consultation and cancellation of appointment. Evidence: resources identified by /appointments/{id}; reading uses GET; cancellation uses POST /cancel; errors use 200 with envelope. Classification: level 1 with partial level 2 elements. Risk: inconsistent observability and retry handling. Next action: adopt DELETE or cancellation according to domain semantics, HTTP status and , maintaining old route during migration.

11.23 Migration strategy

Migration must start with a journey of value and not with a total rewrite of the catalog. Select operations with high support costs, risk of duplication or difficulty in evolution. Inventory gateway consumers, volumes, payload dependencies, internal codes, and policies. Define success metrics before publishing the new interface.

The new surface can coexist with the old one. An adapter translates level 0 messages to level 2 resources and methods; Old responses are preserved for legacy clients. Contracts have dates, deprecation policies and usage telemetry. Irreversible changes only occur after evidence of migration.

should be added when there is a use case. Starting with self, next, prev and process relations links allows you to test tooling and consumers. Dynamic actions can be introduced into flows with relevant states. The team avoids creating a broad framework before demonstrating benefit.

Risk-and compatibility-driven incremental migration roadmap
Figure 7 - Evolution between levels can be incremental, compatible and risk-driven.

11.24 Observability and troubleshooting

Interface maturity changes the quality of operational signals. At level 0, metrics per POST /service aggregate all intents; It is necessary to extract operation from the body or add a business attribute. At level 1, routes distinguish resources, but actions can remain hidden. At level 2, method, route template and status offer standardized dimensions. At level 3, followed relationships can reveal transitions and journeys.

Logs must record method, route template, status, latency, response source, correlation ID, consumer and identifier when allowed. Avoid using the concrete URI as a metric label, as high cardinality IDs degrade observability systems. Use /transfers/{id} as a dimension and preserve the identifier only in protected logs or traces.

Troubleshooting needs to separate contract and transport. A timeout occurs before any classification; a 405 indicates that an HTTP component responded; a 409 could represent domain conflict; a 200 with internal error suggests level 0 contract or poor fit. For gateways, confirm whether the response was produced by the proxy, the policy, or the backend.

Table 10 - Useful symptoms when investigating interfaces at different levels.
SymptomHypothesisEvidence to collect
Everything appears as a routeLevel 0 Generic Endpointoperation field, extraction policy and trace
GET changes stateLevel 2 semantics violateddomain logs and repeated tests
Retry duplicates operationPOST without deduplicationidempotency key and transactional records
Link exists but failsOutdated or unauthorized controlrepresentation, status and authorization decision
405 on gatewayBlocked or unpublished methodAllow, route and upstream configuration
200 with problemLegacy envelope or transformationbody, policy chain and backend status

11.25 Case studies and labs

The following exercises use a fictitious transfer domain. Run only in lab or mock environments. The objective is to observe differences in contracts and behavior; it's not reproducing real data or integrations.

Case study 1 - dispatcher modernization

An API receives POST /transactions with action=CONSULT, action=CREATE and action=CANCEL. All results use 200. Propose resources, methods, and answers. Consider how to preserve old consumers, how to correlate the new transfer, and how to handle timeout after creation. Compare before and after metrics.

Case study 2 - asynchronous process

A transfer may remain under review. Model the request as a , return 202 when processing has not yet finished, and provide a monitor. Then add self, cancel and receipt relationships depending on the state. Verify that the server rejects unauthorized actions even when the link is fabricated.

Laboratory 1 - classification by evidence

  • List all endpoints for a test API and group by journey.
  • Identify operations focused on body or verbs in the path.
  • Rate each journey, not just the entire API.
  • Record evidence of resources, methods, status, headers and .
  • Produce recommendations prioritized by risk and value.

Lab 2 - Test

  • Run GET repeatedly and confirm that there is no requested effect on the domain.
  • Repeat PUT and DELETE and observe the desired effect.
  • Simulate concurrent update with ETag and If-Match.
  • Cause validation, conflict, absence and unavailability; compare status and .
  • Inspect gateway and backend to find out which component produced each response.

Lab 3 - client

  • Start at an entry point and look for relationships, without concatenating paths.
  • Only perform actions present in the .
  • Change the target of a relationship on the server without modifying the client.
  • Remove a state change transition and observe the behavior.
  • Capture metrics of followed relationships and transition failures.

Chapter summary

The describes evolution at four levels. Level 0 focuses operations on messages sent to a generic . Level 1 introduces resources and identifiers. Level 2 uses through methods, status, headers, cache and preconditions. Level 3 adds controls that guide transitions in the current state.

The model is useful for diagnosis and planning, but does not measure all attributes of a platform. Security, reliability, governance, performance, documentation and compatibility require their own analysis. It also does not replace the REST constraints described by Fielding. An interface can reach level 3 without obtaining all of the style's architectural properties.

Evolution must be driven by risk and value. Stable resources improve identity; improve interoperability and operation; can reduce coupling to URLs and flow rules. Each step has costs and depends on the consumer ecosystem. The goal is not to achieve a score, but to build predictable, evolving and observable interfaces.

Assessment checklist

  • Are operations concentrated on an and differentiated by body?
  • Do domain concepts have stable resources and identifiers?
  • Do URIs represent resources rather than function names?
  • Do methods respect security and ?
  • Do status codes correctly identify success, client error, and server failure?
  • Do creations, asynchronous processes, and preconditions use appropriate headers?
  • Do errors have a structured format and do not expose sensitive data?
  • Do retries consider and deduplication?
  • Do representations expose links and actions with defined relationships?
  • Do clients really interpret relationships or continue to encode URLs?
  • Does evaluation separate , REST constraints, and quality attributes?
  • Do gateway, backend and domain preserve the same semantics?
  • Do metrics use route templates and distinguish origin from response?
  • Does the migration have consumer inventory, telemetry and a deprecation plan?

Review exercises

  • Explain why using JSON and POST does not determine the level of an API.
  • Classify an interface with multiple paths, all handled by POST, and justify.
  • Model retrieval, creation and cancellation of transfers at levels 0, 1 and 2.
  • Describe a situation where an API level 2 is adequate and level 3 is not suitable.
  • Explain how ETag and If-Match contribute to a level 2 interface.
  • Propose relationships for a four-state approval process.
  • Differentiate between absence of link and lack of authorization on the server.
  • Compare to stateless and REST cache constraints.
  • Explain why OpenAPI does not certify idempotent behavior.
  • Create a migration plan for a single used by five consumers.
  • Describe a troubleshooting script for 200 containing internal error.
  • Build an evidence matrix to evaluate an API at the gateway and backend.

Glossary

Essential chapter glossary.
TermDefinition
AffordanceIndication of a possible action and how to execute it in the context of a representation.
EndpointPoint of interaction exposed by an API, normally associated with URI and method.
HATEOASUse of hypermedia to guide application state and upcoming transitions.
HypermediaMedia that contains controls, relationships or links capable of guiding navigation and actions.
IdempotencyProperty by which equivalent repetitions produce the same intended effect.
Link relationshipRelationship that defines the meaning of a link between the context and the target.
POXPlain Old XML; in RMM, it represents proprietary messages carried by a generic endpoint, even when the modern format is JSON.
Problem DetailsStandardized format for representing Problem Detailss in HTTP APIs.
ResourceIdentifiable abstraction that can have server-controlled representations and state.
RepresentationTransferred data that describes the current or intended state of a resource.
Richardson Maturity ModelFour-level model to observe capability adoption, HTTP semantics, and hypermedia.
RMMAcronym for Richardson Maturity Model.
HTTP SemanticsShared meaning of methods, codes, headers, and other protocol elements.
URI TemplateSyntax for expressing parameterized URIs that can be expanded by clients.
WebLinkingStandardized model for expressing links and relationships in web messages.

Technical references

The references below should be read together. Fowler's article presents the model; Fielding's dissertation provides the architectural basis of REST; the RFCs define the interoperable semantics used in the examples.

[1] FOWLER, Martin. : steps toward the glory of REST. 2010. Available at: martinfowler.com/articles/richardsonMaturityModel.html.

[2] FIELDING, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. University of California, Irvine, 2000. Chapter 5: Representational State Transfer.

[3] IETF. RFC 9110 - . 2022.

[4] IETF. RFC 9111 - HTTP Caching. 2022.

[5] IETF. RFC 8288 - Web Linking. 2017.

[6] IETF. RFC 6570 - . 2012.

[7] IETF. RFC 9457 - for HTTP APIs. 2023.

[8] IANA. Link Relations Registry. Register of standardized relationships for links.

[9] OpenAPI Initiative. OpenAPI Specification. Specification for describing HTTP APIs.

[10] IETF. RFC 6902 - JavaScript Object Notation (JSON) Patch. 2013.

[11] IETF. RFC 7386 - JSON Merge Patch. 2014.

[12] IETF. RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests. 2014. Obsolete as an aggregate document, but historically relevant; the current semantics are consolidated in RFC 9110.

End of the chapter The next step of the course is to delve deeper into the description and governance of API contracts, connecting HTTP modeling, OpenAPI, validation, compatibility and pipeline automation.