Links are useful for:
- Hiding implementation details
Let’s say we’re loading a Post and its “Top Comments”. On Day One, we might eager load the data like so:
This fetches all the data in a single request. But after some UI testing, we decide to add a “show comments” button. This way our page can load more quickly - it only needs to load the Post initially, and loading Top Comments can be deferred. We want to lazy load the relationship.
How would we do this? We could bake this logic into our next request:
But this requires the client to have knowledge of what a “Top Comment” is. If this logic ever changed, we’d have to update every client - our desktop app, mobile apps, reports, etc… Not to mention, third parties who just want to display Top Comments are required to have this knowledge and update their implementations as well.
Maybe we could hide what “Top Comment” means with a special endpoint:
But now clients need to know to hit this special endpoint instead of
/comments endpoint. How would they know? What if
top_comments had special caching rules and shouldn’t be used for
The main problem here is there is no way to guarantee our lazy-loaded data will match our eager loaded data. Whether we fetch the Post and its Top Comments in a single request, or lazy-load that data in a separate request, the same data should always be returned.
Links solve this problem. When we fetch the Post, the
relationship will contain a URL. Clients can simply follow that URL to
lazy-load the same data. We can now change the definition of a Top
Comment - 500 upvotes, factor in recency, apply downvotes - and no
clients need to change. They simple continue to follow a Link.
1.1 Linking Relationships
When defining a relationship, we get a Link for free:
And when customizing a relationship with
params, our Link will be
Note: if you use the
scope block directly, it may cause incorrect
links. Avoid using
scope directly and instead use
pre_load if possible.
To manually generate a Link:
To avoid a Relationship Link altogether:
2 Resource Endpoints
To generate links, we need to associate a Resource to a URL. By default, this happens automatically:
Which would generate links to
Associating a Resource to an Endpoint serves two purposes. We’ve gone over link generation. But we also want to make sure we’re not linking to something that doesn’t actually exist. That’s why we perform Endpoint Validation.
If we tried to access the above resource at a
We’d get a
Graphiti::Errors::InvalidEndpoint error. Endpoint
validation ensures that our auto-generated Links are actually valid.
To change the endpoint associated to a Resource:
Or to alter only the path:
Or to alter only the actions supported:
A resource may be accessible by multiple endpoints. Maybe
is also used at
/top_posts. We want to keep all auto-generated links
/posts (the primary endpoint), but allow accessing
PostResource from the
To turn off automatically generated links:
3.2 Endpoint Validation
To turn off Endpoint Validation:
To only render links when requested in the URL with
3.4 Custom Endpoint URLs
To change the URL associated with a Resource:
To generate a Relationship Link manually: