跳到主要内容

API 校验

Entity.validate() 会在规范化和反规范化过程中被调用。返回 undefined 表示没有错误;如果有错误,则返回字符串形式的错误信息。

字段检查​

校验发生在 Entity.process() 之后、Entity.fromJS() 之前,因此它操作的是 POJO,而不是类的实例。

这里我们可以确保包含 title 字段,并且其类型符合预期。

Fixtures
GET /article/1
{"id":"1","title":"first"}
GET /article/2
{"id":"2"}
GET /article/3
{"id":"3","title":{"complex":"second","object":5}}
▶api/Article
import { Entity, RestEndpoint } from '@data-client/rest';

export class Article extends Entity {
  id = '';
  title = '';

  static validate(processedEntity) {
    if (!Object.hasOwn(processedEntity, 'title')) return 'missing title field';
    if (typeof processedEntity.title !== 'string') return 'title is wrong type';
  }
}

export const getArticle = new RestEndpoint({
  path: '/article/:id',
  schema: Article,
});
▶ArticlePage
结果
Store▶

全部字段检查​

validateRequired() 可用于检查所有已定义的字段是否都存在。

Fixtures
GET /article/1
{"id":"1","title":"first"}
GET /article/2
{"id":"2"}
GET /article/3
{"id":"3","title":{"complex":"second","object":5}}
▶api/Article
import { Entity, RestEndpoint, validateRequired } from '@data-client/rest';

export class Article extends Entity {
  id = '';
  title = '';

  static validate(processedEntity) {
    return validateRequired(processedEntity, this.defaults);
  }
}

export const getArticle = new RestEndpoint({
  path: '/article/:id',
  schema: Article,
});
▶ArticlePage
结果
Store▶

部分结果​

校验的另一个绝佳用途是混合使用返回不完整对象的 endpoint。当某些字段占用大量带宽,或者对后端来说计算开销很大时,这通常很有用。

可以考虑使用 validateRequired 来减少代码量。

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
import { Entity, RestEndpoint } from '@data-client/rest';
import { Temporal } from 'temporal-polyfill';

export class ArticlePreview extends Entity {
  id = '';
  title = '';

  static key = 'Article';
}
export const getArticleList = new RestEndpoint({
  path: '/article',
  schema: [ArticlePreview],
});

export class ArticleFull extends ArticlePreview {
  content = '';
  createdAt = Temporal.Instant.fromEpochMilliseconds(0);

  static schema = {
    createdAt: Temporal.Instant.from,
  };

  static validate(processedEntity) {
    if (!Object.hasOwn(processedEntity, 'content')) return 'Missing content';
  }
}

export const getArticle = new RestEndpoint({
  path: '/article/:id',
  schema: ArticleFull,
});
▶ArticleDetail
结果
Store▶