[Frontend React] Simplificando Integrações de Backend com Swagger, Axios e React Query
Hoje em dia, ao lidarmos com integrações de API no backend, muitas vezes nos deparamos com o desafio de criar manualmente funções que tratam essas requisições e retornam os dados. No entanto, esse processo pode ser aprimorado e automatizado para aumentar a eficiência do desenvolvimento.
Geralmente, a criação dessas funções de requisição é dispersa em diferentes partes da aplicação, ou até mesmo acumulada em uma única página. É comum usarmos o useEffect
para realizar as chamadas à API e atualizar o estado da aplicação, como demonstrado no código a seguir:
const [todos, setTodos] = useState([])
async function getTodos(){
const { data } = await api.get('/todos)
setTodos(data)
}
useEffect(() => {
getTodos()
}, [])
Também existem meios melhores como usando o react query, mas também no final temos o mesmo trabalho de escrever as nossas requisições, mas ainda sim precisamos criar uma função para fazer a requisição e usar essa função dentro de uma useQuery da aplicação, e se falarmos disso em uma grande escala estamos falando de um enorme trabalho de gerenciamento, isso porque não falamos quando o pessoal de backend decide mudar o que vem de resposta dentro da aplicação e você só vai ter noção disso quando o cliente falar que a tela não ta funcionando
async function getUsers(){
const { data } = await api.get('/user')
return data
}
function App(){
const queryClient = useQueryClient()
const query = useQuery({ queryKey: ['users'], queryFn: getUsers })
return (
<div>
<ul>
{query.data?.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
)
}
No entanto, todos esses desafios podem ser superados com o uso de ferramentas de automação, como o Swagger.
O Swagger é uma ferramenta poderosa que auxilia na documentação de APIs. Se você ou sua empresa ainda não estão utilizando o Swagger para simplificar a integração com o backend, continue lendo para descobrir como essa ferramenta pode ser valiosa.
Neste exemplo, vou mostrar como usar o Swagger para buscar informações dos repositórios do Axios e React Query.
O Swagger de exemplo estará em um repositório no final do post, onde você pode encontrar mais detalhes.
Para começar, usaremos três bibliotecas que automatizarão a integração com a API: Axios, React Query e Orval.
- O Axios é uma biblioteca para fazer requisições HTTP. Vamos criar uma instância customizada para lidar com os tipos de entrada e saída das requisições.
- O React Query é uma biblioteca que simplifica a gestão de cache e adota conceitos de query e mutation, semelhantes ao GraphQL.
- O Orval é uma ferramenta responsável por converter o Swagger em requisições tipadas para nossa instância do React Query, usando o Axios personalizado.
Primeiro, vamos configurar nossa instância do Axios. Isso envolve criar uma abstração para simplificar as requisições e configurar cabeçalhos, como mostrado abaixo:
// axios.ts
import Axios, { AxiosError, AxiosRequestConfig } from 'axios';
import { servers } from './swagger.json';
const API_BASE_URL = servers[0].url;
export const AxiosInstance = Axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json'
}
});
export function request<T>(config: AxiosRequestConfig): Promise<T> {
const source = Axios.CancelToken.source();
const promise = AxiosInstance({
...config,
cancelToken: source.token,
}).then(({ data }) => data);
// @ts-ignore
promise.cancel = () => {
source.cancel('Query was cancelled');
};
return promise;
};
export type ErrorType<Error> = AxiosError<Error>;
// Exmplo de um bearer token no header da aplicação
// AxiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`;
Agora, configure o React Query criando um QueryClient no arquivo raiz da sua aplicação e envolvendo sua aplicação com o QueryClientProvider:
// ...
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
function Main() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
)
}
Finalmente, configure o Orval. Crie um arquivo orval.config.cjs
na raiz da sua aplicação com a configuração abaixo:
const path = require('path');
/** @type {import('orval').Options} */
module.exports = {
backend: {
output: {
mode: 'single',
prettier: true,
client: 'react-query',
target: path.resolve(__dirname, './query.ts'),
override: {
mutator: {
path: require.resolve('./axios.ts'),
name: 'request'
},
query: {
useQuery: true,
// useInfinite: true,
// useInfiniteQueryParam: 'page'
},
header: () => '//@ts-nocheck\n'
}
},
input: {
target: require.resolve('./swagger.json')
}
}
};
Algumas observações sobre essa configuração que você precisa entender antes dos próximos passos:
mode: sigle
é para criar um único arquivo ja com todas as definições das queries.target: ...(./query.ts)
é o nome do arquivo de saída com as configurações.mutator
indica que vamos usar uma instância personalizada, e para isso passamos o caminho do arquivo e o nome da instância que será usada.query
é para informar quais os tipos de querys vamos usar como ouseQuery
, mas ha também outros tipos como para paginação usando asuseInfinite
input -> target
é o arquivo swagger de entrada que será lido.
Agora, adicione um script ao seu package.json para executar o Orval:
// package.json
"orval": "orval --config ./orval.config.cjs"
Após rodar o comando orval
, um arquivo query.ts
será gerado com definições de todas as requisições do Swagger. Você pode usar essas queries facilmente em sua aplicação, como mostrado abaixo:
import { Fragment } from 'react'
import { useGetAxiosAxios, useGetTanStackQuery } from './query'
export default function App() {
const { data, isLoading, isError, refetch } = useGetAxiosAxios()
if (isLoading || !data) {
return <h1>loading...</h1>
}
if (isError) {
return <h1>error...</h1>
}
return (
<Fragment>
<h1> Repo: {data.name}</h1>
<p>
{data.description}
</p>
<strong>{data.subscribers_count}</strong>
<strong>{data.stargazers_count}</strong>
<strong>{data.forks_count}</strong>
<button onClick={() => refetch()}>Refetch data</button>
</Fragment>
)
}
Agora, seu código está mais limpo e fácil de entender. As queries geradas pelo Swagger simplificam a integração com o backend e mantêm suas tipagens atualizadas automaticamente.
Lembre-se de manter seu Swagger atualizado sempre que houver alterações na API do backend para evitar problemas de tipagem.
Uma boa adição é executar o tsc
após rodar o comando orval
para verificar erros de tipagem.
orval --config ./orval.config.cjs && tsc
Espero que este post tenha sido útil para vocês. Se tiver dúvidas ou sugestões de melhoria, deixe um comentário.
Abaixo está os links das ferramentas que foram utilizadas junto a um repositório de exemplo com esse exemplo do post
LinkedIn: Felipe Bergaschi
Repositório: github
Documentações:
Axios: Site | github
Swagger: Site
React query: Site | github
Orval:Site | github