Executando verificação de segurança...
1

[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 o useQuery, mas ha também outros tipos como para paginação usando as useInfinite
  • 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

Carregando publicação patrocinada...