DEV Community

Romildo Junior
Romildo Junior

Posted on • Edited on

6 3

Minio como alternativa ao S3 em aplicações Node

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.

Minio Docs page

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]')); 
Enter fullscreen mode Exit fullscreen mode

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,
);
Enter fullscreen mode Exit fullscreen mode

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 })
  }
}
Enter fullscreen mode Exit fullscreen mode

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,
});
Enter fullscreen mode Exit fullscreen mode

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]')); 
Enter fullscreen mode Exit fullscreen mode

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'
});
Enter fullscreen mode Exit fullscreen mode

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,
);
Enter fullscreen mode Exit fullscreen mode

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.

Referências

SurveyJS custom survey software

Build Your Own Forms without Manual Coding

SurveyJS UI libraries let you build a JSON-based form management system that integrates with any backend, giving you full control over your data with no user limits. Includes support for custom question types, skip logic, an integrated CSS editor, PDF export, real-time analytics, and more.

Learn more

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay