Como Consumir uma API CRUD com React + TypeScript no Frontend

Posted by

Consumar uma API REST criada com NestJS e Prisma no frontend usando React e TypeScript é uma prática essencial para desenvolvedores modernos. Este artigo aborda desde o setup inicial até a implementação completa de componentes reutilizáveis, serviços e páginas que se comunicam com os endpoints da sua API.

O foco é oferecer uma arquitetura clara, escalável e alinhada com padrões atuais do ecossistema React.

Requisitos mínimos para começar

Antes de avançar, certifique-se de ter:

  • Conhecimento básico em React, TypeScript e Vite.
  • Backend em NestJS rodando localmente ou na nuvem (por exemplo, http://localhost:3000).
  • Node.js instalado, além de um gerenciador de pacotes como npm ou yarn.
  • Um editor de código configurado, como VSCode.

Configuração inicial do projeto com Vite

Para iniciar o projeto frontend, use o comando abaixo para criar uma aplicação React com TypeScript:

npm create vite@latest frontend-crud --template react-ts

Acesse a pasta do projeto e instale as dependências:

cd frontend-crud
npm install

Instale bibliotecas importantes:

npm install axios react-router-dom @tanstack/react-query

Adicione suporte ao ambiente de desenvolvimento:

npm install --save-dev @types/react-router-dom

Definição de variáveis de ambiente

Crie um arquivo .env na raiz do projeto para armazenar a URL da API:

VITE_API_URL=http://localhost:3000

No código, você pode acessar essa variável com:

import.meta.env.VITE_API_URL

Estrutura recomendada de pastas

Organize o projeto da seguinte forma para facilitar manutenção e escalabilidade:

src/
├── hooks/               # Hooks personalizados
├── components/          # Componentes reutilizáveis
├── pages/               # Páginas principais
├── services/            # Serviços Axios
├── types/               # Interfaces TypeScript
├── App.tsx              # Roteamento principal
└── main.tsx             # Entry point

Definição de tipos com TypeScript

Defina interfaces em types/index.ts baseadas nos modelos do backend NestJS:

export interface User {
  id: number;
  email: string;
  profile?: Profile;
}

export interface Profile {
  id: number;
  bio: string;
  userId: number;
}

Criação de serviços com Axios

Crie um serviço genérico para chamadas HTTP:

// src/services/api.ts
import axios from 'axios';

const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
});

export default api;

Exemplo específico para usuários:

// src/services/userService.ts
import api from './api';
import { User } from '../types';

const endpoint = '/users';

export const getUsers = async () => {
  const response = await api.get(endpoint);
  return response.data;
};

export const getUserById = async (id: number) => {
  const response = await api.get(`${endpoint}/${id}`);
  return response.data;
};

Criação de componentes reutilizáveis

Tabela dinâmica

Crie uma tabela genérica para exibir dados:

// src/components/Table.tsx
import React from 'react';

interface TableProps<T> {
  data: T[];
  columns: { key: keyof T; label: string }[];
}

const Table = <T extends { id: number }>({ data, columns }: TableProps<T>) => {
  return (
    <table>
      <thead>
        <tr>{columns.map(col => <th key={col.key}>{col.label}</th>)}</tr>
      </thead>
      <tbody>
        {data.map(item => (
          <tr key={item.id}>
            {columns.map(col => <td key={col.key}>{item[col.key]}</td>)}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

export default Table;

Formulário dinâmico com validação

Use react-hook-form para formulários:

// src/components/UserForm.tsx
import React from 'react';
import { useForm } from 'react-hook-form';

interface UserFormProps {
  onSubmit: (data: { email: string; bio: string }) => void;
}

const UserForm = ({ onSubmit }: UserFormProps) => {
  const { register, handleSubmit } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} placeholder="Email" required />
      <input {...register('bio')} placeholder="Bio" />
      <button type="submit">Salvar</button>
    </form>
  );
};

export default UserForm;

Implementação das páginas do CRUD

Exemplo de página de listagem de usuários:

// src/pages/UsersPage.tsx
import React, { useEffect, useState } from 'react';
import { User } from '../types';
import { getUsers, deleteUser } from '../services/userService';
import Table from '../components/Table';

const columns = [
  { key: 'id', label: 'ID' },
  { key: 'email', label: 'Email' },
  { key: 'bio', label: 'Bio' },
];

const UsersPage = () => {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    const fetchUsers = async () => {
      const data = await getUsers();
      setUsers(data);
    };
    fetchUsers();
  }, []);

  const handleDelete = async (id: number) => {
    await deleteUser(id);
    setUsers(users.filter(user => user.id !== id));
  };

  return (
    <div>
      <h2>Usuários</h2>
      <Table data={users} columns={columns} />
    </div>
  );
};

export default UsersPage;

Configuração do roteamento com React Router

Implemente rotas com react-router-dom:

// src/App.tsx
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import UsersPage from './pages/UsersPage';
import OrdersPage from './pages/OrdersPage';

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/users" element={<UsersPage />} />
        <Route path="/orders" element={<OrdersPage />} />
      </Routes>
    </BrowserRouter>
  );
};

export default App;

Tratamento de erros

Implemente um hook para mostrar mensagens de erro:

// src/hooks/useErrorToast.ts
import { useState } from 'react';

export const useErrorToast = () => {
  const [error, setError] = useState<string | null>(null);

  const showError = (message: string) => {
    setError(message);
    setTimeout(() => setError(null), 3000);
  };

  return { error, showError };
};

Intercepte erros com Axios:

// src/services/api.ts
import axios from 'axios';

const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
});

api.interceptors.response.use(
  response => response,
  error => {
    console.error('API Error:', error);
    return Promise.reject(error);
  }
);

export default api;

Build e deploy do projeto

Gere a build final com:

npm run build

Você pode fazer o deploy em plataformas como Vercel, Netlify ou hospedar em servidores estáticos como Nginx.

Veja neste artigo como criar um vps barato e 100% performático, está pagina que você está vendo esta utilizando este servidor.

Conclusão

Este guia apresentou uma maneira eficiente de consumir uma API REST construída com NestJS e Prisma utilizando React e TypeScript. Com uma estrutura organizada, tipagem segura e chamadas HTTP bem definidas, é possível construir interfaces amigáveis e funcionais integradas ao backend.

Se desejar, posso ajudar a adicionar autenticação, paginação ou testes unitários ao frontend.

Leave a Reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *