Skip to main content
Version: 4.5

Resources with nested structure

Say you have a foreignkey author, and an array of foreign keys to contributors.

First we need to model what this will look like by adding members to our Resource defintion. These should be the primary keys of the entities we care about.

Next we'll need to extend the schema definition provided by asSchema().

asSchema

resources/ArticleResource.ts

import { Resource, schemas, AbstractInstanceType } from 'rest-hooks';
import { UserResource } from 'resources';

export default class ArticleResource extends Resource {
readonly id: number | undefined = undefined;
readonly content: string = '';
readonly author: number | null = null;
readonly contributors: number[] = [];

pk() {
return this.id?.toString();
}
static urlRoot = 'http://test.com/article/';

static schema = {
author: UserResource.asSchema(),
contributors: [UserResource.asSchema()],
};
}

Upon fetching the nested items will end up in the cache so they can be retrieved with useCache()

ArticleList.tsx

import { useResource } from 'rest-hooks';
import ArticleResource from 'resources/ArticleResource';

export default function ArticleList({ id }: { id: number }) {
const articles = useResource(ArticleResource.listShape(), { id });

return (
<React.Fragment>
{articles.map(article => (
<ArticleInline key={article.pk()} article={article} />
))}
</React.Fragment>
);
}

function ArticleInline({ article }: { article: ArticleResource }) {
const author = useCache(UserResource.detailShape(), { id: article.author });
// some jsx here
}

Circular dependencies

If two or more Resources include each other in their schema, you can dynamically override one of their asSchema() to avoid circular imports.

resources/ArticleResource.ts

import { Resource, schemas, AbstractInstanceType } from 'rest-hooks';
import { UserResource } from 'resources';

export default class ArticleResource extends Resource {
readonly id: number | undefined = undefined;
readonly content: string = '';
readonly author: number | null = null;
readonly contributors: number[] = [];

pk() {
return this.id?.toString();
}
static urlRoot = 'http://test.com/article/';

static schema = {
author: UserResource.asSchema(),
contributors: [UserResource.asSchema()],
};
}

UserResource.schema = {
posts: [ArticleResource.asSchema()],
};

resources/UserResource.ts

import { Resource } from 'rest-hooks';
// no need to import ArticleResource as the asSchema() override happens there.

export default class UserResource extends Resource {
readonly id: number | undefined = undefined;
readonly name: string = '';
readonly posts: number[] = [];

pk() {
return this.id?.toString();
}
static urlRoot = 'http://test.com/user/';
}