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.