A facilidade em criar buckets e enviar arquivos para o S3 da Amazon é algo fantástico. Armazenar objetos, ao invés de ter um sistema de arquivos, diminui a complexidade e traz uma eficiência à esse tipo de operação.
Um dos problemas da Amazon é o seu valor. Em projetos menores, que não se beneficiam da grande disponibilidade da plataforma, é comum adotar - pelo menos para hospedar a aplicação - a Digital Ocean. Nesse artigo, vamos utilizar uma "s3 própria" por meio do Minio em uma API básica para upload de arquivos, feita com Node.js e Javascript.
Curte uma trilha sonora? Eu fiz esse artigo ouvindo essa playlist no spotify.
O que é o Minio?
Segundo a própria documentação, o Minio é uma tecnologia de armazenamento baseada em objetos, de alta performance. Ele é escrito em Go e tem uma API compatível com o AWS S3.
Vale destacar a questão da compatibilidade. Como veremos, é possível até configurar o cliente do S3 da SDK para Javascript de modo que ele utilize, na verdade, o minio.
Criando a API
Aqui, suponho que você possua um projeto configurado para utilizar ES6 Modules - uma forma simples é por meio do Babel. Caso precise, utilize este template.
O primeiro passo é criar uma API para que possamos testar, no futuro, a funcionalidade. Utilizando express, teríamos algo assim:
import express from 'express';
import { S3 } from 'aws-sdk';
import cors from 'cors';
import morgan from 'morgan';
const app = express();
app.use(cors());
app.use(morgan('dev'));
app.listen(3000, () => console.log('[READY]'));
Depois disso, é necessário criar uma rota que trate o upload de arquivos individuais. Aqui faremos uso do Multer:
app.route('/upload').post(
multer({ storage: multer.memoryStorage() }).single('file'),
uploadHandler,
);
Upload Handler
É nessa função em que utilizamos a API da S3:
const uploadHandler = async (req, res) => {
try {
await s3.putObject({
Bucket: 'tests',
Key: req.file.originalname,
Body: req.file.buffer,
}).promise();
return res
.status(201)
.send({
message: `File "${req.file.originalname}" uploaded`
});
} catch (e) {
console.log(e);
return res
.status(500)
.send({ error: e.message })
}
}
E assim criamos o objeto s3
:
const s3 = new S3({
endpoint: 'http://play.minio.io:9000',
accessKeyId: 'Q3AM3UQ867SPQQA43P2F',
secretAccessKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG',
sslEnabled: false,
s3ForcePathStyle: true,
});
Nesse caso, as credenciais são para o servidor de testes do Minio.
Por que não usar a SDK do Minio para JS? Diga-se de passagem, por design, não existe muita diferença, mas aqui estou fazendo isso para mostrar como adaptar, sem basicamente nenhuma mudança na estrutura do projeto, o serviço utilizado. Isso também é útil para utilizar pacotes como o
multer-s3
.
Dessa forma, o código completo seria o seguinte:
import express from 'express';
import { S3 } from 'aws-sdk';
import cors from 'cors';
import morgan from 'morgan';
const s3 = new S3({
endpoint: 'http://play.min.io:9000',
accessKeyId: 'Q3AM3UQ867SPQQA43P2F',
secretAccessKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG',
sslEnabled: false,
s3ForcePathStyle: true,
});
const app = express();
app.use(cors());
app.use(morgan('dev'));
const uploadHandler = async (req, res) => {
try {
await s3.putObject({
Bucket: 'tests',
Key: req.file.originalname,
Body: req.file.buffer,
}).promise();
return res
.status(201)
.send({
message: `File "${req.file.originalname}" uploaded`
});
} catch (e) {
console.log(e);
return res
.status(500)
.send({ error: e.message })
}
}
app.route('/upload').post(
multer({ storage: multer.memoryStorage() }).single('file'),
uploadHandler,
);
app.listen(3000, () => console.log('[READY]'));
Utilizando a API própria do Minio
Caso você não precise utilizar a API da S3, algumas alterações seriam necessárias. A primeira é a própria definição do objeto "s3". Poderíamos substituir pelo seguinte:
const minioClient = new Minio.Client({
endPoint: 'play.min.io',
port: 9000,
useSSL: true,
accessKey: 'Q3AM3UQ867SPQQA43P2F',
secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG'
});
A segunda seria na utilização desse cliente para realizar o upload, dentro da função uploadHandler, para a seguinte forma:
//...
await minioClient.putObject(
'tests',
req.file.originalname,
req.file.buffer,
);
Considerações
Caso você execute o código criado, é possível realizar upload de arquivos por meio de requisições http para localhost:3000/upload
utilizando multipart/form-data
. O multer faz o trabalho pesado de modo que temos total acesso ao arquivo na memório (atravez do memoryStorage).
Dito isso, utilizamos a SDK da AWS da maneira convencional, contudo o objeto que nos dá acesso à API da S3 é criado com alguns parâmetros importantes - sobretudo o endpoint, que recebe a URL do servidor minio de interesse. Observe que quase nenhuma alteração é necessária, uma vez que o Minio foi estruturado para permitir esse tipo de compatibilidade.
Top comments (0)