Introduction#
It's a way to generate a dedicated endpoint for an entity property.
Let's say you have a User entity that owns a collection of articles. Rather than exposing the articles in the
/users route and have a lot of unnecessary nested data, you might want to directly access the article list with only
the properties you want for that route scope.
Usage#
By decorating the articles property with the @Subresource decorator, you generates 3
routes :
GET:/users/:userId/articles, which will list allarticlesof the givenuserPOST:/users/:userId/articles, which will allow you to join anarticleto thisuser(a newarticleis inserted if noarticle.id is given !)DELETE:/users/:userId/articles/:articleId, which will allow you to remove the relation between the givenuser/article
Let's implement that :
For an entity to be used as a Subresource, it must have an EntityRouter
registered. And if you don't want to generates CRUD routes, you can just provide no arguments to
@EntityRoute just like the example above.
Of course, you can customize your Subresource using SubresourceOptions as optional second argument.
| Option key | Type | Default | Description |
|---|---|---|---|
| operations | SubresourceOperation | ["create", "list", "details", "delete"] | Defines which routes should be generated for this subresource |
| maxDepth | number | undefined | Restrict the depth of subresources nesting allow from this one |
| canHaveNested | boolean | true | Allow this subresource to have nested child subresources |
| canBeNested | boolean | true | Allow this subresource to be used as a child subresource |
- By just specifying "create" as
SubresourceOperation, only thePOST:/users/:userId/articleswould be generated. You get the idea, this works the same for others operations. - A single relation should use the
detailsSubresourceOperationwhereas a collection should use thelistSubresourceOperation.
Nesting#
Subresources are nestable by default, so you could have a GET:/users/:userId/articles/comments by making
Article.comments a subresource as well. And if you're crazy enough, nothing stops you from nesting further with a
GET:/users/:userId/articles/comments/upvotes, etc.
The defaultEntityRouteOptions (passed to the
makers) has a defaultSubresourceMaxDepthLvl: 2.
Max depth#
You can control the max depth using the maxDepth key of SubresourceOptions. Each
maxDepth is independant from each other. If no max depth is defined, it will fallback to the
defaultSubresourceMaxDepthLvl of EntityRouteOptions, and if somehow no
defaultSubresourceMaxDepthLvl is defined, it will default to 2.
Circular#
Circular subresources are disabled by default. You can allow this behavior using the allowCircular key of
SubresourceOptions.
Example: Let's say a user has articles, these articles have both a writers (linking back to the User entity)
and also have a relatedArticles subresources.
By allowing circular subresources (and with the appropriates max depths configured), the route
GET:/users/articles/writers would be generated.
With single relations#
The example above and most use-cases of subresources will be for collection relation
(OneToMany/ManyToMany).
But sometimes you might want a single relation
(OneToOne/ManyToOne)
to be a subresource.
There is actually no difference in usage between single/collection subresources but here's an example for the sake of it.
Let's say you have a User entity that is linked with a config relation. Rather than exposing the config in the
/users route and have a lot of unnecessary nested data, you might want to directly access the config with only the
properties you want for that route scope.
By decorating the config property with the @Subresource decorator, you generates 3 routes
:
GET:/users/:userId/config, which will show you theconfigof the givenuserPOST:/users/:userId/config, which will allow you to join aconfigto thisuser(a newconfigis inserted if noconfig.id is given !)DELETE:/users/:userId/config, which will allow you to remove the relation between the givenuser/config
Format in response#
With the EntityRouteOptions key shouldSetSubresourcesIriOnItem, the corresponding
subresources IRI are added for each items having subresources (without exposing them through
@Groups).
The defaultEntityRouteOptions (passed to the
makers) has a shouldSetSubresourcesIriOnItem: true.
With subresource IRI#
Using the same example from above with User/Article, here's how that would look like :
The articles property will have its subresource IRI displayed in the responses :
With relation exposed#
When exposing the articles property on user.details, the response will differ :
With nested property exposed#
And if you exposed properties from that subresource relation (with @Groups):
This is how the response would look like with User.articles.title exposed :
Metadata#
You can retrieve the RouteSubresourcesMeta registered by an
@EntityRoute decorator by using the
getRouteSubresourcesMetadata function.