Communitygithub.com

Padrões Sanity

Plataforma de conteúdo estruturado — consultas GROQ, definições de esquemas, @sanity/client, Portable Text, manipulação de imagens, listeners em tempo real, mutações, TypeGen

O que é Padrões Sanity?

Este skill fornece um guia completo para trabalhar com a Sanity, uma plataforma de conteúdo estruturado baseada em um content lake em tempo real. Ele abrange desde a configuração básica do cliente com `createClient` e a definição de esquemas tipados usando `defineType` e `defineField`, até consultas avançadas com GROQ, renderização de Portable Text, manipulação de imagens com `@sanity/image-url` e execução de mutações. O skill enfatiza práticas recomendadas e padrões críticos, como o uso obrigatório da propriedade `apiVersion` no cliente, parametrização de consultas GROQ para prevenir injeção, e o manuseio explícito de documentos de rascunho. Além disso, detalha a geração de tipos TypeScript com Sanity TypeGen, garantindo segurança de tipos de ponta a ponta. Ele é ideal para desenvolvedores que trabalham com Sanity Studio, frontends em React, Next.js ou qualquer framework que consuma APIs da Sanity, cobrindo cenários comuns como autenticação, listas em tempo real e otimização de imagens.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/agents-inc/skills/tree/HEAD/src/skills/api-cms-sanity

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Padrões Sanity faz?

Guia Rápido: Use a Sanity para gerenciamento de conteúdo estruturado com consultas GROQ, esquemas tipados via defineType/defineField, e @sanity/client para busca de dados. Sempre defina apiVersion para uma string datada, use useCdn: true para leituras públicas, trate documentos de rascunho explicitamente, use @sanity/image-url para transformações de imagem e renderize rich text com @portabletext/react. Gere tipos TypeScript com sanity typegen generate.


<critical_requirements>

CRÍTICO: Antes de Usar Este Skill

Todo código deve seguir as convenções do projeto no CLAUDE.md (kebab-case, exports nomeados, ordenação de imports, import type, constantes nomeadas)

(Você DEVE sempre definir apiVersion no createClient com uma string datada como '2025-02-19' — omitir isso usa uma API legada que pode quebrar)

(Você DEVE usar useCdn: true para consultas de leitura públicas e useCdn: false ao usar um token ou precisar de dados atualizados)

(Você DEVE usar consultas GROQ parametrizadas ($param) para qualquer valor dinâmico — nunca interpole entrada do usuário em strings GROQ)

(Você DEVE tratar rascunhos explicitamente — documentos de rascunho têm _id prefixado com drafts. e não são retornados por padrão com perspective: 'published')

(Você DEVE usar defineQuery() de groq e atribuir consultas a variáveis nomeadas para geração de tipos TypeGen)

</critical_requirements>


Detecção Automática: Sanity, sanity, @sanity/client, createClient, GROQ, groq, defineType, defineField, defineArrayMember, @sanity/image-url, urlFor, @portabletext/react, PortableText, portable text, block content, sanity.config, sanity.cli, typegen, sanity studio, content lake

Quando usar:

  • Configurando @sanity/client com createClient para busca de dados
  • Escrevendo consultas GROQ (filtros, projeções, junções, ordenação, fatiamento)
  • Definindo esquemas de conteúdo com defineType, defineField, defineArrayMember
  • Renderizando Portable Text (conteúdo de bloco) com @portabletext/react
  • Gerando URLs de imagem com @sanity/image-url (imagens responsivas, recortes, hotspots)
  • Realizando mutações (criar, atualizar, deletar, transações)
  • Configurando listeners em tempo real com client.listen()
  • Gerando tipos TypeScript com Sanity TypeGen

Padrões chave abordados:

  • Configuração do cliente com createClient e configuração de apiVersion
  • Linguagem de consulta GROQ: filtros, projeções, ordenação, fatiamento, junções, referências
  • Definições de esquema: tipos de documento, tipos de objeto, arrays, referências, imagens
  • Renderização de Portable Text com componentes personalizados
  • Construtor de URLs de imagem com imagens responsivas e transformações
  • Mutações: criar, createOrReplace, atualizar, deletar, transações
  • Listeners em tempo real via client.listen()
  • TypeGen para consultas GROQ type-safe com defineQuery()

Quando NÃO usar:

  • APIs exclusivamente GraphQL (a Sanity suporta GROQ principalmente; use o skill GraphQL se necessário)
  • Acesso direto a banco de dados (a Sanity é um content lake hospedado, não um banco de dados)
  • Plataformas CMS que não são Sanity (use o skill dedicado para seu CMS)

Recursos Detalhados:

  • Para frameworks de decisão e tabelas de referência rápida, veja reference.md

Cliente & GROQ:

  • examples/core.md — Configuração do cliente, consultas GROQ, tratamento de erros, TypeGen

Esquemas:

  • examples/schemas.md — defineType, defineField, tipos de documento, tipos de objeto, referências, imagens

Conteúdo Rico:

Mutações & Tempo Real:


Filosofia

A Sanity é uma plataforma de conteúdo estruturado construída em torno de um content lake em tempo real, GROQ (Graph-Relational Object Queries) como sua linguagem de consulta, e o Sanity Studio como um ambiente de edição personalizável.

Princípios fundamentais:

  1. Conteúdo estruturado — O conteúdo é definido por esquemas (defineType, defineField) que descrevem forma, validação e UI editorial. Esquemas são código, não arquivos de configuração.
  2. Consulta com GROQ em primeiro lugar — GROQ permite filtrar, projetar, juntar e remodelar dados em uma única consulta. Diferente de REST ou GraphQL, as consultas GROQ retornam exatamente a forma que você define na projeção.
  3. Conteúdo como dados — Rich text é armazenado como Portable Text (uma especificação baseada em JSON), tornando-o renderizável em qualquer framework frontend sem dependência de fornecedor.
  4. Versionamento de API — Todo cliente deve especificar uma string de data apiVersion. Isso fixa seu código em um comportamento específico da API, evitando que mudanças que quebrem afetem a produção.
  5. Cache CDN — Consultas de leitura públicas usam useCdn: true para respostas em cache na borda. Mutações e leituras autenticadas usam useCdn: false para dados atualizados.
  6. Geração de tipos — Sanity TypeGen gera tipos TypeScript tanto dos seus esquemas quanto das consultas GROQ, permitindo segurança de tipos de ponta a ponta, do modelo de conteúdo ao frontend.

Quando usar a Sanity:

  • Sites e aplicações orientados a conteúdo (blogs, sites de marketing, documentação)
  • Projetos que precisam de edição colaborativa em tempo real em um studio personalizável
  • Entrega de conteúdo multicanal (web, mobile, IoT) de uma única fonte de conteúdo
  • Equipes que desejam consultas de conteúdo type-safe com GROQ e TypeGen

Quando NÃO usar:

  • Dados transacionais que exigem garantias ACID (use um banco de dados)
  • Conteúdo gerado por usuário em escala massiva (a Sanity é otimizada para conteúdo editorial)
  • Projetos que precisam de um CMS auto-hospedado (o content lake da Sanity é hospedado, embora o Studio seja open source)

Padrões Principais

Padrão 1: Configuração do Cliente com createClient

Configure @sanity/client com ID do projeto, dataset, versão da API e preferência de CDN. Sempre defina apiVersion como uma string datada e useCdn explicitamente.

import { createClient } from "@sanity/client";

export const client = createClient({
  projectId: process.env.SANITY_PROJECT_ID!,
  dataset: process.env.SANITY_DATASET!,
  apiVersion: "2025-02-19", // Fixar em uma data de versão de API específica
  useCdn: true, // true para leituras públicas, false para dados autenticados/atualizados
});

Para configuração de cliente duplo (público + preview com token), veja examples/core.md.


Padrão 2: Consultas GROQ com Filtros e Projeções

Consultas GROQ combinam filtros, projeções, ordenação e fatiamento. Sempre use defineQuery() para TypeGen e $param para valores dinâmicos.

import { defineQuery } from "groq";

const POST_BY_SLUG_QUERY = defineQuery(`
  *[_type == "post" && slug.current == $slug][0]{
    _id, title, body, "author": author->{name, image}
  }
`);
const post = await client.fetch(POST_BY_SLUG_QUERY, { slug: "my-post" });

Nunca interpole entrada do usuário em strings GROQ — sempre use parâmetros $param para prevenir injeção GROQ. Para consultas avançadas (consultas combinadas, projeções condicionais), veja examples/core.md.


Padrão 3: Definições de Esquema com defineType e defineField

Defina a estrutura do conteúdo com defineType, defineField e defineArrayMember de "sanity" para segurança de tipos e UI do Studio.

import { defineType, defineField } from "sanity";

export const postType = defineType({
  name: "post",
  type: "document",
  fields: [
    defineField({
      name: "title",
      type: "string",
      validation: (r) => r.required(),
    }),
    defineField({ name: "slug", type: "slug", options: { source: "title" } }),
  ],
});

Para esquemas completos (imagens com hotspot, arrays, referências, previews, tipos de objeto), veja examples/schemas.md.


Padrão 4: Renderização de Portable Text

Renderize conteúdo de bloco com @portabletext/react. Defina PortableTextComponents personalizados para blocos não padrão (imagens, código) e marks (links, destaques).

import { PortableText } from "@portabletext/react";
<PortableText value={body} components={components} />;

Não use o pacote obsoleto @sanity/block-content-to-react. Para exemplos completos de componentes, veja examples/rich-content.md.


Padrão 5: Construtor de URLs de Imagem

Use @sanity/image-url para gerar URLs de imagem otimizadas e responsivas com suporte a recorte e hotspot.

import { createImageUrlBuilder } from "@sanity/image-url";
const builder = createImageUrlBuilder(client);
export function urlFor(source: SanityImageSource) {
  return builder.image(source);
}
// Uso: urlFor(image).width(800).auto("format").url()

Para padrões de srcSet responsivo e transformações de imagem, veja examples/rich-content.md.


Padrão 6: Mutações (Criar, Atualizar, Deletar)

Use os métodos de @sanity/client para mutações de documentos. Sempre chame .commit() em patches e transações.

await client.create({ _type: "post", title: "Novo Post" });
await client.patch("post-123").set({ title: "Atualizado" }).commit();
await client.delete("post-123");

Para createOrReplace, createIfNotExists, transações, inserções em arrays e opções de visibilidade, veja examples/mutations.md.


Padrão 7: Listeners em Tempo Real

Inscreva-se em mudanças de documentos com client.listen(). O listener usa apenas a parte de filtro do GROQ — projeções e ordenação são ignoradas.

const subscription = client.listen(`*[_type == "post"]`).subscribe({
  next: (update) => {
    /* update.transition: 'update' | 'appear' | 'disappear' */
  },
  error: (err) => console.error(err),
});
subscription.unsubscribe(); // Limpeza ao terminar

Para frontends de produção, avalie a Live Content API mais nova como uma alternativa mais simples. Para opções e ressalvas do listener, veja examples/mutations.md.


Padrão 8: TypeGen para GROQ Type-Safe

Configure TypeGen em sanity.cli.ts com overloadClientMethods: true para resultados tipados de client.fetch. Use defineQuery() de "groq" para tornar as consultas detectáveis pelo TypeGen.

// sanity.cli.ts — defina typegen.overloadClientMethods: true
// queries/post-queries.ts — envolva consultas com defineQuery()
// sanity.types.ts — tipos de resultado gerados automaticamente
const posts = await client.fetch(allPostsQuery); // Resultado tipado

Strings de consulta inline sem defineQuery() produzem resultados sem tipo (any). Para configuração completa e fluxo de trabalho do TypeGen, veja examples/core.md.


<decision_framework>

Framework de Decisão

useCdn: true vs false

Os dados são públicos e não personalizados?
├─ SIM → useCdn: true (cache na borda, rápido)
└─ NÃO →
    ├─ Usando um token para leituras autenticadas? → useCdn: false
    ├─ Precisa de dados atualizados em tempo real (preview)? → useCdn: false
    └─ Realizando mutações? → useCdn: false

Tratamento de Rascunhos

Precisa de documentos de rascunho?
├─ SIM → Use perspective: 'previewDrafts' (requer token)
├─ NÃO → Use perspective: 'published' (padrão desde a API v2025-02-19)
└─ Misto (alternar modo de preview)?
    └─ Crie dois clientes: um público (useCdn: true), um preview (token + useCdn: false)

Forma de Retorno da Consulta GROQ

Quantos documentos você espera?
├─ Um (por ID, slug, singleton) → Adicione [0] no final (retorna objeto ou null)
├─ Muitos (lista, feed) → Sem sufixo de fatia (retorna array)
└─ Paginado → Adicione fatia [start...end]

Manipulação de Imagens

Como as imagens devem ser entregues?
├─ Tamanho fixo (thumbnails, avatares) → urlFor(img).width(W).height(H).url()
├─ Responsivo (imagens de artigos) → srcSet com múltiplas larguras
├─ Otimização de formato → .auto('format') para WebP/AVIF
└─ Cortado para proporção → .width(W).height(H).fit('crop')

Seleção de Método de Mutação

Qual operação você precisa?
├─ Criar novo documento → client.create()
├─ Criar ou substituir completamente → client.createOrReplace() (para singletons)
├─ Criar apenas se faltar → client.createIfNotExists()
├─ Atualizar campos específicos → client.patch(id).set({...}).commit()
├─ Remover campos → client.patch(id).unset([...]).commit()
├─ Múltiplas alterações relacionadas → client.transaction()...commit()
└─ Deletar documento → client.delete(id)

</decision_framework>


<red_flags>

BANDEIRAS VERMELHAS

Problemas de Alta Prioridade:

  • apiVersion ausente no cliente — Omitir apiVersion usa comportamento de API legado que pode mudar sem aviso. Sempre fixe em uma string de data.
  • Interpolação de string em consultas GROQ — Interpolar entrada do usuário em strings GROQ permite injeção GROQ. Sempre use parâmetros $param.
  • Usar useCdn: true com um token — Respostas em cache CDN ignoram tokens de autenticação. Consultas autenticadas devem usar useCdn: false.
  • Acessar documentos de rascunho sem um token — Rascunhos (documentos drafts.*) requerem um token de API e perspective: 'previewDrafts'. Sem um token, os rascunhos são invisíveis.

Problemas de Média Prioridade:

  • Buscar todos os campos com {...} quando apenas alguns são necessários — Buscar demais desperdiça largura de banda e eficiência de cache CDN. Projete apenas os campos que precisa.
  • Falta de .commit() em patches — client.patch(id).set({...}) sem .commit() não faz nada — a mutação nunca é enviada.
  • Não usar defineQuery() para consultas GROQ — TypeGen não pode gerar tipos para consultas que não estão envoltas em defineQuery() ou atribuídas a variáveis nomeadas.
  • ID do projeto ou dataset fixo no código — Use variáveis de ambiente; valores fixos impedem a troca de ambiente e vazam detalhes do projeto.
  • Usar @sanity/block-content-to-react obsoleto — Substituído por @portabletext/react. O pacote antigo não é mantido.

Erros Comuns:

  • Esquecer _key em itens de array em mutações — Cada item em um array da Sanity deve ter um campo _key único. Mutações sem _key falharão.
  • Usar _id com client.create() — create() gera um _id aleatório. Se você especificar _id e o documento existir, ocorrerá erro. Use createOrReplace() ou createIfNotExists() para operações idempotentes.
  • Não tratar o caso onde [0] retorna null — Uma consulta GROQ com [0] retorna null se nenhum documento corresponder. Sempre verifique se o resultado não é null antes de acessar propriedades.

</red_flags>

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Habilidades Relacionadas