URL Patterns
Common REST urls resemble the following:
/static_root/
- GET - retrieve list of resources
- optionally include search params
/static_root/?size=20&page=5
- optionally include search params
- POST - create resource
- GET - retrieve list of resources
/static_root/[id]/
- GET - retrieve one entity matching 'id'
- PUT - update entire entity
- PATCH - update partial entity
- DELETE - delete entity
Resource comes out of the box with support for these patterns simply
by defining the static urlRoot
property on a Resource.
export default ArticleResource extends Resource {
readonly id: string = '';
//...
pk() { return this.id; }
static urlRoot = '/articles/';
}
It does this by using that urlRoot
static property in two static methods:
- url(urlParams)
- handles most Endpoints
- listUrl(searchParams)
- used in create() and list()
ArticleResource.listUrl();
// "/articles/"
ArticleResource.listUrl({ size: 20, page: 5 });
// "/articles/?size=20&page=5"
ArticleResource.url({ id: 5 });
// "/articles/5/"
Customizing the url patterns is typically as easy as overriding either of these methods. However, in more extreme scenarios, key() can be set in a custom Endpoint definition.
Example
A somewhat common pattern is to hold 'sub' resources at nested paths to their 'master'.
We might see something like /articles/[articleId]/comments/
to get the comments for
a given article.
export default class CommentResource extends Resource {
readonly id: string = '';
pk() {
return this.id;
}
// since we won't be using urlRoot to build our urls we
// still need to tell rest hooks how to uniquely identify this Resource
static get key() {
return 'CommentResource';
}
/**
* Get the url for a Resource
*/
static url<T extends typeof Resource>(
this: T,
urlParams: { articleId: string } & Partial<AbstractInstanceType<T>>,
): string {
if (urlParams) {
if (this.pk(urlParams) !== undefined) {
return `/articles/${articleId}/comments/${this.pk(urlParams)}`;
}
}
// since we're overriding the url() function we must keep the type the
// same, which means we might not get urlParams
throw new Error('Comments require articleId to retrieve');
}
/**
* Get the url for many Resources
*/
static listUrl(searchParams: { articleId: string }): string {
if (searchParams && Object.keys(searchParams).length) {
const { articleId, ...realSearchParams } = searchParams;
const params = new URLSearchParams(realSearchParams as any);
// this is essential for consistent url strings
params.sort();
return `/articles/${articleId}/comments/?${params.toString()}`;
}
throw new Error('Comments require articleId to retrieve');
}
}
CommentResource.listUrl();
// error thrown
CommentResource.listUrl({ articleId: '5' });
// "/articles/5/comments/"
CommentResource.listUrl({ articleId: '5', size: 20, page: 6 });
// "/articles/5/comments/?size=20&page=6"
CommentResource.url({ id: 5 });
// error thrown
CommentResource.url({ articleId: '5', id: '23' });
// "/articles/5/comments/23/"