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)