Skip to main content
Version: 5.0

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 definition. These should be the primary keys of the entities we care about.

Next we'll provide a definition of nested members in the schema member.

static schema

resources/ArticleResource.ts

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

export default class ArticleResource extends Resource {
readonly id: number | undefined = undefined;
readonly content: string = '';
readonly author: UserResource = UserResource.fromJS({});
readonly contributors: number[] = [];

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

static schema = {
author: UserResource,
contributors: [UserResource],
};
}

ArticleList.tsx

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

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

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

function UserPreview({ user }: { user: UserResource }) {
return <span>{user.username} {user.email}</span>
}

Circular dependencies

If both Resources are in distinct files, this must be handled with care.

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

resources/ArticleResource.ts

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

export default class ArticleResource extends Resource {
readonly id: number | undefined = undefined;
readonly content: string = '';
readonly author: UserResource = UserResource.fromJS({});
readonly contributors: number[] = [];

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

static schema = {
author: UserResource,
contributors: [UserResource],
};
}

// we set the schema here since we can correctly reference ArticleResource
UserResource.schema = {
posts: [ArticleResource],
};

resources/UserResource.ts

import { Resource } from '@rest-hooks/rest';
import type { ArticleResource } from 'resources';
// we can only import the type else we break javascript imports
// thus we change the schema of UserResource above

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

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