Validação da API
Entity.validate() é chamado durante a normalização e a desnormalização.
undefined indica que não há erro, e uma string com a mensagem de erro indica que há um erro.
Verificação de campo
A validação acontece depois de Entity.process(), mas antes de Entity.fromJS(), e portanto opera sobre POJOs, e não sobre uma instância da classe.
Aqui podemos garantir que o campo title esteja presente e seja do tipo esperado.
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
Resultado
Store▶
Verificação de todos os campos
validateRequired() pode ser usado para verificar se todos os campos definidos estão presentes.
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
Resultado
Store▶
Resultados parciais
Outro ótimo uso da validação é combinar endpoints que retornam objetos incompletos. Isso costuma ser útil quando alguns campos consomem muita banda ou são computacionalmente caros para o backend.
Considere usar validateRequired para reduzir código.
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
Resultado
Store▶