Summary List Endpoints
Sometimes you have a list endpoint that includes only a subset of fields.
In this case we can use Entity.validate() to ensure we have the full response when needed (detail views), while keeping our state DRY and normalized to ensure data integrity.
Fixtures
GET /article
[{"id":"1","title":"first"},{"id":"2","title":"second"}]
GET /article/1
{"id":"1","title":"first","content":"long","createdAt":"2011-10-05T14:48:00.000Z"}
GET /article/2
{"id":"2","title":"second","content":"short","createdAt":"2011-10-05T14:48:00.000Z"}
▶api/Article.ts
class ArticleSummary extends Entity {readonly id: string = '';readonly title: string = '';pk() {return this.id;}// this ensures `Article` maps to the same entitystatic key = 'Article';}class Article extends ArticleSummary {readonly content: string = '';readonly createdAt: Date = new Date(0);static schema = {createdAt: Date,};static validate(processedEntity) {return (validateRequired(processedEntity, this.defaults) ||super.validate(processedEntity));}}const BaseArticleResource = createResource({path: '/article/:id',schema: Article,});const ArticleResource = {...BaseArticleResource,getList: BaseArticleResource.getList.extend({ schema: [ArticleSummary] }),};
▶ArticleDetail.tsx
Detail data in nested entity
It's often better to move expensive data into another entity to simplify conditional logic.
api/Article.ts
class ArticleSummary extends Entity {
readonly id: string = '';
readonly title: string = '';
readonly content: string = '';
readonly createdAt: Date = new Date(0);
static schema = {
createdAt: Date,
};
pk() {
return this.id;
}
// this ensures `Article` maps to the same entity
static key = 'Article';
}
class Article extends ArticleSummary {
readonly meta: ArticleMeta = ArticleMeta.fromJS({});
static schema = {
...super.schema,
meta: ArticleMeta,
}
static validate(processedEntity) {
return (
validateRequired(processedEntity, this.defaults) ||
super.validate(processedEntity)
);
}
}
class ArticleMeta extends Entity {
readonly viewCount: number = 0;
readonly likeCount: number = 0;
readonly relatedArticles: ArticleSummary[] = [];
static schema = {
relatedArticles: [ArticleSummary],
}
}
const BaseArticleResource = createResource({
path: '/article/:id',
schema: Article,
});
const ArticleResource = {
...BaseArticleResource,
getList: BaseArticleResource.getList.extend({ schema: [ArticleSummary] }),
};