Servidor de upload de imagens com Cloudflare R2
📋 Sobre • 🚀 Tecnologias • ⚙️ Configuração • 📦 Instalação • 🏃 Executando • 📚 Padrões • 🔄 Fluxo • 👤 Autor
Servidor back-end que faz parte de uma aplicação fullstack
desenvolvido para gerenciar uploads de imagens
utilizando Cloudflare R2 como provedor de armazenamento.
O projeto implementa uma API REST com Fastify,
seguindo padrões de arquitetura em camadas e utilizando TypeScript para garantir type-safety.
Important
Essa aplicação trabalha em conjunto com a aplicação front-end
>
Front-end
- ✅ Upload de imagens via stream
- ✅ Validação de arquivos (tamanho máximo: 4MB)
- ✅ Integração com Cloudflare R2
- ✅ CORS configurado
- ✅ Validação de variáveis de ambiente com Zod
- ✅ Arquitetura modular e escalável
- Fastify (v5.1.0) - Framework web rápido e eficiente
- @aws-sdk/client-s3 (v3.700.0) - Cliente S3 para integração com Cloudflare R2
- @aws-sdk/lib-storage (v3.700.0) - Biblioteca para upload de streams
- Zod (v3.23.8) - Validação de schemas TypeScript-first
- @fastify/multipart (v9.0.1) - Plugin para upload de arquivos
- @fastify/cors (v10.0.1) - Plugin CORS
- TypeScript (v5.7.2) - Superset JavaScript com tipagem estática
- tsx (v4.19.2) - Executor TypeScript para desenvolvimento
- @types/node (v22.10.0) - Tipos TypeScript para Node.js
Crie um arquivo .env na raiz do projeto com as seguintes variáveis:
CLOUDFLARE_ACCESS_KEY_ID=seu_access_key_id
CLOUDFLARE_SECRET_ACCESS_KEY=seu_secret_access_key
CLOUDFLARE_BUCKET=nome_do_seu_bucket
CLOUDFLARE_ACCOUNT_ID=seu_account_id
CLOUDFLARE_PUBLIC_URL=https://seu-dominio.com- Acesse o Cloudflare Dashboard
- Vá em R2 > Manage R2 API Tokens
- Crie um novo token com permissões de leitura e escrita
- Copie o
Access Key IDeSecret Access Key - Obtenha o
Account IDno dashboard do Cloudflare - Configure o bucket e a URL pública do R2
- Node.js (versão 22 ou superior)
- pnpm (gerenciador de pacotes)
- Clone o repositório:
git clone https://github.com/emmanuelmarcosdeoliveira/upload-widget-server
cd upload-widget-server- Instale as dependências:
pnpm install- Configure as variáveis de ambiente (veja seção Configuração)
pnpm devO servidor estará rodando em http://localhost:3333
Upload de imagem
Request:
- Content-Type:
multipart/form-data - Body: arquivo de imagem (máximo 4MB)
Response (201):
{
"url": "https://seu-dominio.com/nome-do-arquivo.jpg"
}Response (400):
{
"message": "Invalid file provided." | "File size must be a maximum of 4MB.."
}O projeto segue uma arquitetura em camadas:
src/
├── server.ts # Configuração do servidor Fastify
├── env.ts # Validação de variáveis de ambiente
├── routes/ # Rotas da aplicação
│ └── upload-image.ts
├── functions/ # Casos de uso/regras de negócio
│ └── upload-image-to-storage.ts
└── storage/ # Camada de abstração de armazenamento
├── storage.ts # Interface StorageProvider
└── providers/
└── r2-storage.ts # Implementação para Cloudflare R2
- Provider Pattern: Abstração do provedor de armazenamento através da interface
StorageProvider - Dependency Injection: Injeção de dependências para facilitar testes e manutenção
- Schema Validation: Validação de variáveis de ambiente e dados com Zod
- Stream Processing: Upload de arquivos via streams para melhor performance
- Modo
stricthabilitado - Target: ES2022
- Module: Node16
- Lib: ES2023
Diagrama do fluxo principal de upload de imagens:
sequenceDiagram
participant Cliente
participant Fastify as Fastify Server
participant Multipart as @fastify/multipart
participant Route as uploadImageRoute
participant UploadService as UploadImageToStorage
participant Storage as R2StorageProvider
participant R2 as Cloudflare R2
Cliente->>Fastify: POST /uploads (multipart/form-data)
Fastify->>Multipart: Processa arquivo
Multipart->>Route: Arquivo validado (max 4MB)
alt Arquivo inválido ou ausente
Route->>Cliente: 400 Bad Request
else Arquivo válido
Route->>Storage: Instancia R2StorageProvider
Route->>UploadService: Instancia UploadImageToStorage(storage)
Route->>UploadService: execute({ name, contentStream, contentType })
UploadService->>UploadService: Valida request com Zod
UploadService->>Storage: uploadFileAsStream({ path, stream, contentType })
Storage->>Storage: Sanitiza nome do arquivo
Storage->>R2: Upload stream via AWS SDK
R2-->>Storage: Upload concluído
Storage-->>UploadService: { url }
UploadService-->>Route: { url }
Route->>Cliente: 201 Created { url }
end
- Cliente envia requisição POST com arquivo multipart
- Fastify recebe e processa via plugin multipart
- Route valida tamanho do arquivo (máximo 4MB)
- UploadImageToStorage valida dados com Zod
- R2StorageProvider sanitiza nome e faz upload para Cloudflare R2
- Cloudflare R2 armazena o arquivo
- Cliente recebe URL pública do arquivo
Desenvolvido por Emmanuel Oliveira
Este projeto foi desenvolvido como parte dos estudos na RocketSeat.
Emmanuel Oliveira
developed by 💫 Emmanuel Oliveira
© Todos os Direitos Reservados
Clique na seta abaixo e veja como você pode contribuir para o projeto
Como fazer uma contribuição ao Projeto ?
Familiarize-se com a documentação do projeto, que geralmente inclui guias de instalação.Explore o código do projeto para entender sua estrutura e funcionamento.
Faça um Fork
Crie uma cópia (fork) do repositório original em sua conta do GitHub.
Clone o Repositório
Isso criará uma cópia local do projeto, onde você poderá fazer suas modificações.
Crie uma Nova Branch:
Crie uma nova branch para isolar suas alterações.
Isso facilita a organização do seu trabalho e a criação de pull requests.
Faça as Alterações:
Crie funcionalidades, mude estilos ou resolva bugs que iram contribuir para a melhoria do Projeto.
Crie um Pull Request:
Inclua uma descrição clara das suas alterações e explique como elas resolvem o problema ou melhoram o projeto.
Solicitação: Envie um pull request para o repositório original, solicitando que suas alterações sejam incorporadas ao projeto.
Revise e Responda a Feedback:
Colabore: Os mantenedores do projeto podem solicitar alterações ou fornecer feedback sobre o seu código.
😁Obrigado por chegar até aqui!
Released in 2025 This project is under the MIT license
