Enterprise Java

When to Use Affordance vs. Link in Hypermedia Controls

Hypermedia as the engine of application state (HATEOAS) brings a new level of discoverability and self-documentation to REST APIs. In Spring HATEOAS, two key concepts play a central role in enriching your API responses with navigable metadata: Link and Affordance. Understanding when to use each—and how they differ—is crucial for building intuitive, flexible APIs that clients can understand and act on without relying on out-of-band documentation.

Understanding the Basics

What is a Link?

A Link in Spring HATEOAS represents a navigable hyperlink that a client can follow. It might point to another resource or to a collection of resources. Each Link typically includes a rel (relation) type that describes its purpose in context (e.g., self, next, update, etc.).

Example:

Link link = Link.of("/orders/123").withRel("self");

What is an Affordance?

An Affordance builds on a Link by describing what actions are possible at the linked URI. This goes beyond just navigating to a resource—it tells the client what HTTP operations are available (e.g., POST, PUT, DELETE) and includes metadata such as input fields, constraints, and expected formats.

Example:

Link linkWithAffordance = Link.of("/orders/123")
    .andAffordance(Affordances.of(OrderController.class).updateOrder(null, 123L));

This link not only tells the client how to get the order, but also how to update it.

Key Differences Between Link and Affordance

FeatureLinkAffordance
PurposeNavigationAction and interaction
HTTP VerbTypically GETAny (GET, POST, PUT, DELETE, PATCH, etc.)
Input MetadataNoneIncludes form structure, input fields, constraints
Self-descriptive APIPartialFull (with method semantics and expectations)
Support in HAL-FORMSLimited (only navigation)Full (used for rendering forms and available actions)

When to Use Each

✅ Use Link When:

  • You only want to provide navigation to another resource.
  • You are linking to read-only endpoints (e.g., GET /users/123).
  • You don’t need to describe possible state changes or operations.

Example Use Case:
Linking from an order list to an individual order detail page.

orderModel.add(Link.of("/orders/123").withSelfRel());

✅ Use Affordance When:

  • You want the client to understand available actions (e.g., “submit”, “update”, “cancel”).
  • You’re building a hypermedia form or supporting HAL-FORMS.
  • You want to generate dynamic UI from API metadata.

Example Use Case:
Enabling clients to submit an update to an order without separate documentation.

orderModel.add(Link.of("/orders/submit").withRel("submit"));

In a HAL-FORMS response, this affordance would be rendered as a form with proper input fields.

Best Practices

  1. Start with Links: Use simple Link objects for read-only navigation.
  2. Add Affordances Where Needed: Introduce Affordance when you want to support client interaction (especially PUT, POST, DELETE).
  3. Be Intentional with rel: Whether adding a link or affordance, clearly define the relationship type (e.g., update, delete, submit-form).
  4. Avoid Overloading Clients: Don’t add affordances to every link—use them where actions are expected or useful.
  5. Test with HAL-FORMS Clients: If you’re exposing affordances, test with tools that understand and render HAL-FORMS (like Spring HATEOAS HAL browser).

Common Pitfall: Using Link When You Need More

Developers often create a link expecting the client to know how to POST to it or what fields are required. This violates the HATEOAS principle. Use affordances to make this self-descriptive:

Not ideal:

orderModel.add(
    linkTo(methodOn(OrderController.class).getOrder(123L))
        .withSelfRel()
        .andAffordance(afford(methodOn(OrderController.class).updateOrder(null, 123L)))
);

Better with affordance:

orderModel.add(
    Link.of("/orders/submit")
        .withRel("submit")
        .andAffordance(afford(methodOn(OrderController.class).submitOrder(null)))
);

Summary

If You Need To…Use LinkUse Affordance
Provide navigation✅ (optional)
Describe allowed operations (e.g., PUT)
Enable form generation via HAL-FORMS
Keep response lightweight

In short, use Link for direction and Affordance for interaction. By using them wisely, you’ll create APIs that are not just consumable—but discoverable and self-describing.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button