Um app React Native corporativo nao quebra apenas por causa de tela mal feita. Muitas vezes ele quebra porque a API foi desenhada como se o cliente fosse sempre um navegador estavel, com rede perfeita, usuario paciente e versao sempre atualizada. No mobile, a realidade e outra: a rede cai, a resposta demora, o app volta do background, a pessoa toca duas vezes no botao, a versao antiga continua instalada e a tela precisa explicar erro sem suporte tecnico do lado.
Por isso, contrato de API para mobile precisa ser mais cuidadoso do que uma lista de endpoints. Ele deve definir sucesso, erro, validacao, conflito, paginacao, retry, idempotencia, upload, autenticacao, contexto ativo e compatibilidade. O objetivo e que o app consiga reagir bem quando tudo da certo e tambem quando algo da errado.
Este artigo organiza um caminho pratico para quem usa React Native no app e Spring Boot no backend. O foco e reduzir retrabalho entre mobile e API, melhorar UX e evitar que cada tela invente seu proprio jeito de interpretar respostas.
1. API mobile e parte da experiencia do usuario
Quando uma API retorna um erro confuso, o app nao tem como criar uma experiencia boa sozinho. Se a resposta nao diz qual campo falhou, a tela mostra mensagem generica. Se o status HTTP e sempre 500, o app nao sabe diferenciar falha temporaria de erro de validacao. Se a lista nao pagina direito, a tela fica lenta. Se a acao nao e idempotente, uma repeticao pode criar duplicidade.
Em produto corporativo, isso vira custo operacional. O usuario nao fala "o contrato da API esta ruim". Ele fala que o app travou, que nao salvou, que duplicou, que perdeu dados ou que nao entende a mensagem. A origem pode estar no backend.
2. Separe contrato publico de implementacao interna
O primeiro cuidado e nao vazar a estrutura interna do backend para o app. Entidade JPA, nome de tabela, stack trace, classe Java e excecao tecnica nao deveriam ser contrato mobile. O app precisa de DTOs pensados para consumo externo:
- campos estaveis e nomeados para a tela;
- tipos previsiveis;
- datas em formato combinado;
- identificadores claros;
- status de negocio legivel;
- campos opcionais bem documentados;
- ausencia de dados internos desnecessarios.
Essa separacao permite que o backend evolua por dentro sem quebrar o app a cada refatoracao. O termo DTO existe justamente para proteger essa fronteira.
3. Use status HTTP como sinal, nao como detalhe decorativo
O RFC 9110 organiza a semantica do HTTP, incluindo metodos, status e comportamento esperado. Para o app, isso importa porque status HTTP e o primeiro sinal de decisao. Um desenho simples ajuda:
200ou201para sucesso real;204quando a acao conclui sem corpo de resposta;400para requisicao invalida ou validacao geral;401para sessao ausente ou invalida;403para usuario autenticado sem permissao;404para recurso inexistente ou fora do escopo permitido;409para conflito de estado;422, quando adotado pelo contrato, para erro semantico de validacao;429para limite de uso;500ou503para falhas inesperadas ou indisponibilidade.
O ponto nao e decorar codigo. E garantir que o app consiga decidir: pedir login, mostrar validacao, tentar de novo, bloquear acao, atualizar dados ou orientar contato com suporte.
4. Erro precisa ter formato previsivel
Um dos maiores ganhos para mobile e padronizar envelope de erro. Em vez de cada endpoint responder de um jeito, defina campos fixos, como:
code: codigo estavel de erro para o app;message: mensagem segura para exibicao ou fallback;fields: erros por campo quando for validacao;correlationId: identificador para suporte e log;retryable: dica se a tentativa pode ser repetida;details: informacao tecnica controlada, nunca stack trace cru.
Com isso, o app consegue mapear erro de campo, abrir toast, mostrar estado vazio, acionar logout ou registrar falha com contexto. O artigo validacao e erros em APIs REST aprofunda a parte backend desse desenho.
5. Spring Boot deve centralizar validacao e tratamento de erro
No Spring Boot, o caminho pratico e evitar tratamento manual espalhado em cada controller. A documentacao do Spring Framework organiza controllers REST, validacao e tratamento de excecoes em camadas que podem ser padronizadas. Em projetos reais, isso normalmente passa por DTOs de entrada, Bean Validation, exceptions de dominio e um handler central.
O ganho para mobile e consistencia. A tela de formulario nao deveria adivinhar se o erro vem como texto, lista, mapa, HTML ou stack trace. Ela deveria receber o mesmo formato em todos os fluxos.
Essa decisao tambem ajuda testes. Quando o contrato de erro e padrao, a equipe testa menos combinacoes exoticas e mais comportamento de negocio.
6. Paginacao precisa combinar com scroll mobile
Lista mobile e diferente de relatorio de escritorio. A pessoa rola, filtra, volta da tela de detalhe, muda rede, atualiza e espera continuidade. Uma API de lista precisa definir:
- tamanho maximo e padrao da pagina;
- ordenacao estavel;
- filtros aceitos;
- campo para proxima pagina ou cursor;
- total, quando fizer sentido;
- comportamento quando itens mudam durante a navegacao;
- limites para busca textual.
Para listas que mudam muito, cursor pode ser melhor do que pagina numerica. Para listas administrativas simples, pagina numerica pode bastar. O importante e nao deixar o app descobrir no susto que a pagina 2 repete item da pagina 1 ou que a ordenacao muda sem criterio.
7. TanStack Query depende de contrato previsivel
O artigo TanStack Query no React Native mostra como organizar cache, queries e mutations. Mas a biblioteca nao conserta contrato ruim. Ela fica muito melhor quando a API tem:
- IDs estaveis;
- filtros claros;
- paginacao consistente;
- erros previsiveis;
- status que indicam retry;
- payload de resposta suficiente para atualizar cache;
- mutations com retorno consistente.
Query key boa nasce de contrato bom. Se a API mistura filtro, contexto e permissao sem padrao, o cache do app tambem fica confuso.
8. Idempotencia evita duplicidade em rede instavel
No mobile, a pessoa pode tocar duas vezes, perder a resposta, voltar do background ou reenviar uma acao depois de erro de rede. Se a API nao protege comandos importantes, o resultado pode ser duplicidade: dois cadastros, duas aprovacoes, dois anexos, duas mensagens.
Nem toda operacao precisa ser idempotente, mas as sensiveis precisam de estrategia. Algumas opcoes:
- usar chave idempotente gerada pelo app para comandos criticos;
- bloquear repeticao por estado de negocio;
- retornar o resultado anterior quando a mesma chave chega de novo;
- usar status de conflito quando a operacao nao pode ser repetida;
- definir timeout e janela de validade da chave.
Esse tema se conecta com offline, fila local e sincronizacao. Se o app tem fila local, idempotencia deixa de ser luxo.
9. Retry precisa ser uma politica combinada
Retry automatico pode salvar a experiencia ou piorar um incidente. A API e o app precisam combinar quando repetir e quando parar. Exemplo pratico:
- erro de rede pode entrar em retry controlado;
401deve acionar fluxo de sessao ou refresh;403nao deve ficar repetindo;409pede atualizar estado ou mostrar conflito;429precisa respeitar limite e espera;500pode ter retry com backoff, mas nao infinito.
Quando cada tela decide sozinha, surgem loops e carga desnecessaria. Quando o contrato define retryable e correlationId, a investigacao fica mais limpa.
10. Versao de app e versao de API precisam conversar
App mobile antigo continua instalado por semanas ou meses. A API nao pode assumir que todo mundo atualizou ontem. Por isso, evolucao de contrato precisa considerar compatibilidade:
- adicionar campos sem quebrar clientes antigos;
- evitar remover campos usados por versoes ainda ativas;
- aceitar payload antigo durante janela de transicao;
- informar versao minima suportada quando necessario;
- bloquear versoes inseguras ou incompativeis com mensagem clara;
- monitorar uso por versao do app.
O portal ja trata isso em compatibilidade entre app mobile e API. Contrato de API bom nao pensa apenas no release de hoje; pensa tambem nos binarios que continuam em campo.
11. Upload e anexo merecem contrato proprio
Enviar foto ou arquivo pelo app nao deveria ser apenas jogar multipart no endpoint e torcer. Um contrato bom define:
- tamanho maximo;
- tipos aceitos;
- compressao esperada;
- metadados obrigatorios;
- timeout e retry;
- estado do processamento;
- mensagens para arquivo invalido;
- limpeza de anexos temporarios.
O artigo upload de fotos e anexos no app React Native aprofunda esse fluxo. Para a API, o importante e tratar upload como processo, nao como detalhe do formulario.
12. Contexto ativo precisa estar explicito
Em app corporativo, quase toda chamada depende de contexto: empresa, unidade, contrato, projeto, turma, equipe ou perfil. Esse contexto precisa ficar claro no contrato, seja por rota, parametro, header controlado ou corpo de requisicao.
O app nao deveria depender de contexto escondido no servidor sem saber o que esta acontecendo. Isso dificulta cache, debug e suporte. Ao mesmo tempo, o backend deve validar se o usuario pode acessar aquele contexto. Esconder menu no app nao basta.
Esse ponto conversa com navegacao autenticada e rotas por perfil e seguranca mobile.
13. Observabilidade com correlationId poupa horas
Quando uma pessoa informa que o app falhou, o suporte precisa ligar app, API e log. Sem correlationId, a investigacao vira busca manual por horario aproximado, usuario e endpoint. Com correlationId, o app pode exibir ou enviar um identificador que o backend tambem registrou.
Um contrato simples pode incluir:
- header de requisicao com identificador gerado pelo app ou gateway;
- correlationId na resposta de erro;
- log estruturado no backend;
- evento de analytics sem dados sensiveis;
- mensagem de suporte com codigo curto.
Isso conecta UX com operacao. A pessoa recebe uma mensagem melhor e a equipe tecnica encontra a falha com menos tentativa.
14. Checklist para revisar contrato mobile
- DTOs de entrada e saida estao separados das entidades internas?
- Status HTTP indicam o tipo real de resultado?
- Envelope de erro e padrao em todos os endpoints?
- Erros de campo chegam em formato que o formulario consegue exibir?
- Listas tem paginacao, ordenacao e filtros estaveis?
- Mutations retornam dados suficientes para atualizar cache?
- Acoes criticas tem idempotencia ou protecao contra duplicidade?
- Retry e conflito tem regra clara?
- Versoes antigas do app continuam compativeis durante transicao?
- Upload tem limite, tipo, erro e estado de processamento definidos?
- Contexto ativo e permissao sao validados no backend?
- Respostas de erro carregam correlationId para suporte?
15. Quando vale diagnosticar antes de codar mais tela
Se o app ja tem varias telas consumindo API, erros diferentes por endpoint, duplicidade ocasional, cache confuso, retry manual e suporte sem codigo de rastreio, talvez o problema nao esteja no React Native. Pode estar no contrato entre app e backend.
Um diagnostico tecnico pode revisar endpoints, DTOs, status, erro, paginacao, autenticacao, contexto, upload e fluxo offline antes que o app acumule excecoes locais. Para apoiar essa revisao, o Checklist de API REST serve como material pratico de conferencia.
Contrato de API bom nao aparece para o usuario. E justamente por isso funciona: a tela salva, lista, tenta de novo, explica erro e continua operando sem transformar cada falha de rede em crise.
Referencias editoriais: RFC 9110 - HTTP Semantics, Spring Framework - Annotated Controllers, TanStack Query - React Native e Android Developers - Data layer.
Termos tecnicos desta leitura
Alguns conceitos aparecem com frequencia neste tema. Abrir o glossario ajuda a comparar definicoes, exemplos e leituras relacionadas sem sair do contexto do artigo.