Olá, devs! Neste post, vamos aprender como fazer upload de uma imagem em uma aplicação Next.js com TypeScript para um bucket na Cloudflare utilizando presigned URLs. Vamos dividir o tutorial em etapas para facilitar o entendimento.
O que é uma Presigned URL?
Uma Presigned URL é uma URL temporária gerada para permitir que usuários façam upload ou download de arquivos diretamente em um serviço de armazenamento, como o Amazon S3 ou Cloudflare R2, sem a necessidade de expor as credenciais de acesso no cliente. Essa URL inclui credenciais temporárias e permissões específicas, como tempo de expiração e tipo de ação permitida (upload ou download).
Vantagens de Usar Presigned URLs:
- Segurança: As credenciais não são expostas no frontend.
- Controle: A URL pode ser configurada para expirar após um determinado tempo.
- Simplicidade: Facilita o processo de upload/download, delegando ao cliente a responsabilidade de transferir os arquivos.
O que Vamos Precisar?
Este artigo necessita de conhecimento intermediário/avançado em Next.js
- Uma aplicação Next.js configurada com TypeScript.
- Uma conta na Cloudflare e acesso ao Cloudflare R2.
Passo 1: Configurando o Cloudflare R2
Primeiro, precisamos configurar o nosso bucket na Cloudflare R2.
- Acesse o painel da Cloudflare e navegue até a seção R2.
- Copie seu ID da conta.
- Crie um novo bucket e anote o nome do bucket, pois vamos precisar dele mais tarde.
- Crie um novo token de API, dê um nome ao token e permissões de gravação/leitura.
- Copie Access Key ID e Secret Access Key para Clientes S3 para interagir com o bucket utilizando a SDK da AWS.
Adicione política de CORS no seu bucket
Para que a aplicação consiga realizar o upload para dentro do bucket no R2, é necessário liberar as seguintes origens, métodos e headers:
[ { "AllowedOrigins": [ "http://localhost:3000" ], "AllowedMethods": [ "GET", "PUT" ], "AllowedHeaders": [ "Content-Type" ] } ]
Passo 2: Criando a Aplicação Next.js
Vamos começar criando uma nova aplicação Next.js utilizando o comando npx create-next-app@latest
:
npx create-next-app@latest
Ao executar o comando acima, o CLI do Next.js fará as seguintes perguntas, e você deve respondê-las conforme as sugestões:
-
What is your project named? (upload-r2)
- Responda com o nome desejado para a sua aplicação. Por exemplo,
upload-r2
.
- Responda com o nome desejado para a sua aplicação. Por exemplo,
-
Would you like to use TypeScript?
- Resposta: Yes
- Explicação: Escolha "yes" para habilitar o suporte ao TypeScript na sua aplicação.
-
Would you like to use ESLint with this project?
- Resposta: Yes
- Explicação: ESLint é uma ferramenta útil para manter a qualidade do código, ajudando a identificar e corrigir problemas de estilo e erros de programação.
-
Would you like to use Tailwind CSS with this project?
- Resposta: Yes
- Explicação: Para este tutorial, estamos focando em usar a biblioteca
shadcn/ui
para estilizar os componentes, então Tailwind CSS é um requisito.
-
Would you like to use
src/
directory with this project?- Resposta: Yes
- Explicação: Usar um diretório
src/
ajuda a organizar melhor os arquivos de código-fonte, separando-os de outros arquivos de configuração e metadados.
-
Would you like to use
App Router
(recommended)?- Resposta: No
- Explicação: Para manter as coisas simples, usaremos a estrutura de diretórios padrão. O diretório
app/
pode não ser necessário para a maioria dos projetos neste estágio.
-
Would you like to customize the default
import alias
(@/*)?- Resposta: No
- Explicação: O alias de importação
@/
é uma convenção comum que facilita os caminhos de importação relativos, tornando o código mais legível e fácil de manter.
Após a instalação das dependências do Next.js, acesse a aplicação e abra no VSCode:
cd upload-r2 code .
Passo 3: Configurando Variáveis de Ambiente
No arquivo .env.local
da sua aplicação Next.js, adicione as seguintes variáveis de ambiente com as informações do Cloudflare R2:
CLOUDFLARE_ACCOUNT_ID=your-account-id AWS_ACCESS_KEY_ID=your-access-key-id AWS_SECRET_ACCESS_KEY=your-secret-access-key AWS_BUCKET_NAME=your-bucket-name
Inicie a aplicação:
npm run dev
Passo 4: Instalando Dependências Necessárias
Vamos precisar do SDK da AWS para interagir com o Cloudflare R2, pois ele é compatível com o S3. Instale com o seguinte comando:
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
Passo 5: Criando a Função para Gerar Presigned URL
Crie um arquivo em pages/api/presigned-url.ts
para gerar a presigned URL:
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { NextApiRequest, NextApiResponse } from 'next'; const accountId = process.env.CLOUDFLARE_ACCOUNT_ID const client = new S3Client({ endpoint: `https://${accountId}.r2.cloudflarestorage.com`, region: 'auto', credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID!, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, } }) export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { key } = req.body; // key pode ser o nome da imagem if (!key) { return res.status(400).json({ error: 'File key is required.' }) } const signedUrl = await getSignedUrl(client, new PutObjectCommand({ Bucket: process.env.AWS_BUCKET_NAME, Key: key }), { expiresIn: 60 // URL válida por 1 minuto }) res.status(200).json({ signedUrl }) }
Passo 6: Utilizando shadcn/ui
Vamos começar adicionando o shadcn/ui na aplicação utilizando o comando:
npx shadcn-ui@latest init
Ao executar o comando acima, o CLI do shadcn/ui fará as seguintes perguntas, e você deve respondê-las conforme as sugestões:
-
Which
style
would you like to use?- Escolha um estilo que deseja utilizar. Por exemplo,
New York
.
- Escolha um estilo que deseja utilizar. Por exemplo,
-
Which color would you like to use as
base color
?- Escolha uma base de cores. Por exemplo,
Slate
.
- Escolha uma base de cores. Por exemplo,
-
Would you like to use
CSS variables
for colors?- Resposta: Yes
- Explicação: Variáveis CSS para cores é útil para o reuso.
Feito isso, estamos prontos para adicionar os componentes. Vamos adicionar os componentes de Label, Input, Button e Sonner para toast:
npx shadcn-ui@latest add label npx shadcn-ui@latest add input npx shadcn-ui@latest add button npx shadcn-ui@latest add sonner
Passo 7: Criando o Formulário de Upload com shadcn/ui
Agora, crie um componente para fazer o upload da imagem utilizando a presigned URL. Crie um arquivo components/UploadForm.tsx
:
import { ChangeEvent, FormEvent, useState } from "react"; import { toast } from "sonner"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; import { Label } from "./ui/label"; export function UploadForm() { const [avatar, setAvatar] = useState<File | null>(null); function handleSelectAvatar(event: ChangeEvent<HTMLInputElement>) { const selectedFile = event.target.files?.[0] || null; setAvatar(selectedFile); } async function handleSubmit(event: FormEvent) { event.preventDefault(); try { if (!avatar) return; const uniqueFileName = `${crypto.randomUUID()}-${avatar.name}`; const response = await fetch('/api/presigned-url', { method: 'POST', headers: { "Content-Type": "application/json", }, body: JSON.stringify({ key: uniqueFileName }) }) const { signedUrl } = await response.json() await fetch(signedUrl, { method: 'PUT', headers: { "Content-Type": avatar.type }, body: avatar }) toast.success('Upload realizado com sucesso!') } catch { toast.error('Ocorreu um erro ao realizar o upload!') } } return ( <form className="flex flex-col gap-4" onSubmit={handleSubmit}> <div> <Label htmlFor="avatar">Avatar</Label> <Input id="avatar" type="file" onChange={handleSelectAvatar} /> </div> <Button>Upload</Button> </form> ) }
Passo 8: Integrando o Componente no Projeto
Finalmente, vamos integrar o componente UploadForm
em uma página do Next.js. Abra pages/index.tsx
e adicione o componente:
import { UploadForm } from "@/components/UploadForm"; import { Toaster } from "@/components/ui/sonner"; export default function Home() { return ( <div className="flex h-screen items-center justify-center"> <div> <UploadForm /> <Toaster /> </div> </div> ); }
Conclusão
Pronto! Agora você tem uma aplicação Next.js com TypeScript capaz de fazer upload de imagens para um bucket na Cloudflare utilizando presigned URLs, e com uma interface estilizada usando shadcn/ui
. Essa abordagem é ótima para garantir segurança e controle sobre os uploads.
Espero que este tutorial tenha sido útil para você. Se tiver alguma dúvida, deixe um comentário abaixo. Até a próxima!
Gostou deste post? Siga-me para mais conteúdos sobre desenvolvimento web e tecnologias! 🚀
Top comments (0)