Pular para o conteúdoPedro Farbo
Lição 3 / 2540 min

Seu Primeiro Servidor Express

Seu Primeiro Servidor Express

Agora que nosso ambiente está configurado, vamos criar nosso primeiro servidor HTTP com Express e TypeScript. Express é o framework web mais popular do Node.js, conhecido por sua simplicidade e flexibilidade.

Instalando Express

bash
# Express e seus tiposnpm install expressnpm install -D @types/express

Hello World com Express

Crie o arquivo src/app.ts:

typescript
import express, { Application, Request, Response } from 'express'; const app: Application = express(); // Middleware para parsear JSONapp.use(express.json()); // Rota raizapp.get('/', (req: Request, res: Response) => {  res.json({    message: 'Bem-vindo à API E-commerce!',    version: '1.0.0',    timestamp: new Date().toISOString(),  });}); // Rota de health checkapp.get('/health', (req: Request, res: Response) => {  res.json({    status: 'ok',    uptime: process.uptime(),    memory: process.memoryUsage(),  });}); export default app;

Agora crie src/server.ts:

typescript
import app from './app'; const PORT = process.env.PORT || 3000; app.listen(PORT, () => {  console.log(`🚀 Servidor rodando em http://localhost:${PORT}`);  console.log(`📝 Ambiente: ${process.env.NODE_ENV || 'development'}`);});

Execute:

bash
npm run dev

Acesse http://localhost:3000 no navegador ou use curl:

bash
curl http://localhost:3000# {"message":"Bem-vindo à API E-commerce!","version":"1.0.0",...}

Entendendo Express

Application

O objeto app é a instância principal do Express:

typescript
import express, { Application } from 'express'; const app: Application = express(); // app.use()    - Adiciona middlewares// app.get()    - Define rota GET// app.post()   - Define rota POST// app.listen() - Inicia o servidor

Request e Response

Toda rota recebe dois objetos principais:

typescript
app.get('/users/:id', (req: Request, res: Response) => {  // Request - Informações da requisição  console.log(req.method);        // 'GET'  console.log(req.path);          // '/users/123'  console.log(req.params.id);     // '123'  console.log(req.query);         // { page: '1', limit: '10' }  console.log(req.body);          // Corpo da requisição (POST/PUT)  console.log(req.headers);       // Headers da requisição   // Response - Métodos para responder  res.status(200);                // Define status code  res.json({ data: 'valor' });    // Envia JSON  res.send('texto');              // Envia texto  res.redirect('/outra-rota');    // Redireciona});

Tipando Request e Response

Para máxima segurança de tipos, podemos tipar o body, params e query:

typescript
import { Request, Response } from 'express'; // Tipos personalizadosinterface CreateUserBody {  name: string;  email: string;  password: string;} interface UserParams {  id: string;} interface ListUsersQuery {  page?: string;  limit?: string;  search?: string;} // Rota tipadaapp.post('/users', (  req: Request<{}, {}, CreateUserBody>,  res: Response) => {  const { name, email, password } = req.body;  // TypeScript sabe que name, email, password são strings}); app.get('/users/:id', (  req: Request<UserParams>,  res: Response) => {  const { id } = req.params;  // TypeScript sabe que id é string}); app.get('/users', (  req: Request<{}, {}, {}, ListUsersQuery>,  res: Response) => {  const { page = '1', limit = '10', search } = req.query;});

Estrutura de Resposta Padronizada

É uma boa prática padronizar suas respostas:

typescript
// src/utils/response.tsexport interface ApiResponse<T = unknown> {  success: boolean;  data?: T;  message?: string;  errors?: string[];  meta?: {    page?: number;    limit?: number;    total?: number;  };} export function successResponse<T>(data: T, message?: string): ApiResponse<T> {  return {    success: true,    data,    message,  };} export function errorResponse(message: string, errors?: string[]): ApiResponse {  return {    success: false,    message,    errors,  };} export function paginatedResponse<T>(  data: T[],  page: number,  limit: number,  total: number): ApiResponse<T[]> {  return {    success: true,    data,    meta: { page, limit, total },  };}

Usando nas rotas:

typescript
import { successResponse, errorResponse } from './utils/response'; app.get('/users/:id', async (req: Request, res: Response) => {  const user = await findUser(req.params.id);   if (!user) {    return res.status(404).json(      errorResponse('Usuário não encontrado')    );  }   res.json(successResponse(user, 'Usuário encontrado'));});

Organizando Rotas

À medida que a aplicação cresce, organize as rotas em arquivos separados:

typescript
// src/routes/user.routes.tsimport { Router, Request, Response } from 'express'; const router = Router(); // GET /usersrouter.get('/', (req: Request, res: Response) => {  res.json({ users: [] });}); // GET /users/:idrouter.get('/:id', (req: Request, res: Response) => {  res.json({ user: { id: req.params.id } });}); // POST /usersrouter.post('/', (req: Request, res: Response) => {  res.status(201).json({ user: req.body });}); // PUT /users/:idrouter.put('/:id', (req: Request, res: Response) => {  res.json({ user: { id: req.params.id, ...req.body } });}); // DELETE /users/:idrouter.delete('/:id', (req: Request, res: Response) => {  res.status(204).send();}); export default router;
typescript
// src/routes/index.tsimport { Router } from 'express';import userRoutes from './user.routes';import productRoutes from './product.routes'; const router = Router(); router.use('/users', userRoutes);router.use('/products', productRoutes); export default router;
typescript
// src/app.tsimport express from 'express';import routes from './routes'; const app = express(); app.use(express.json());app.use('/api', routes); export default app;

Agora suas rotas ficam organizadas:

GET    /api/users
POST   /api/users
GET    /api/users/:id
PUT    /api/users/:id
DELETE /api/users/:id

Middlewares Essenciais

Adicione middlewares comuns:

bash
npm install cors helmet morgannpm install -D @types/cors @types/morgan
typescript
// src/app.tsimport express from 'express';import cors from 'cors';import helmet from 'helmet';import morgan from 'morgan';import routes from './routes'; const app = express(); // Segurança - Define headers HTTP segurosapp.use(helmet()); // CORS - Permite requisições de outros domíniosapp.use(cors({  origin: process.env.FRONTEND_URL || 'http://localhost:3001',  credentials: true,})); // Logger de requisiçõesapp.use(morgan('dev')); // Parser de JSONapp.use(express.json({ limit: '10mb' })); // Parser de URL encodedapp.use(express.urlencoded({ extended: true })); // Rotasapp.use('/api', routes); export default app;

O que cada middleware faz?

MiddlewareFunção
helmetAdiciona headers de segurança (XSS, CSRF, etc)
corsPermite requisições cross-origin
morganLoga requisições no console
express.jsonParseia body JSON
express.urlencodedParseia form data

Testando com REST Client

Instale a extensão REST Client no VS Code e crie requests.http:

http
### Health CheckGET http://localhost:3000/health ### Listar UsuáriosGET http://localhost:3000/api/users ### Criar UsuárioPOST http://localhost:3000/api/usersContent-Type: application/json {  "name": "João Silva",  "email": "joao@email.com",  "password": "123456"} ### Buscar UsuárioGET http://localhost:3000/api/users/1 ### Atualizar UsuárioPUT http://localhost:3000/api/users/1Content-Type: application/json {  "name": "João Silva Atualizado"} ### Deletar UsuárioDELETE http://localhost:3000/api/users/1

Clique em "Send Request" acima de cada requisição para testar.

Exercício Prático

Crie as seguintes rotas para produtos:

typescript
// GET    /api/products        - Listar produtos// POST   /api/products        - Criar produto// GET    /api/products/:id    - Buscar produto por ID// PUT    /api/products/:id    - Atualizar produto// DELETE /api/products/:id    - Deletar produto

Resumo

Nesta aula aprendemos:

  • ✅ Criar servidor Express com TypeScript
  • ✅ Tipar Request e Response
  • ✅ Padronizar respostas da API
  • ✅ Organizar rotas em arquivos separados
  • ✅ Usar middlewares essenciais
  • ✅ Testar rotas com REST Client

Na próxima aula, vamos nos aprofundar em Rotas e Middlewares! 🎯

Gostou do conteúdo? Sua contribuição ajuda a manter tudo online e gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e