Cuando explicas el concepto de bucket, siempre pones de ejemplos los Amazon Buckets que son los mas conocidos. Es un servicio que permite la entrega y recogida de archivos por http metatageados en base de datos lo cual permite encontrarlos facilmente por las aplicaciones. Es algo realmente util cuando en tu conjunto de microservicios hay intercambios de archivos entre los microservicios.

Con mongodb y node es facil crear un bucket.

Partimos de que tenemos un mongodb y nodejs.

Vamos a levantar un microservicio express que recibira las peticiones de entrega y descarga de binarios files por http.

git clone https://github.com/Akaronte/node-mongo-bucket.git
cd node-mongo-bucket
npm i
node index.js

Echemos un vistazo al index.js

index.js
const bodyParser = require('body-parser');
const morgan = require('morgan');
const express = require('express');
const fileUpload = require('express-fileupload');
const cors = require('cors');
const _ = require('lodash');

const app = express();

app.use(fileUpload({
    createParentPath: true
}));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.use(cors({
  origin:['http://localhost:8080'],
  methods:['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
  credentials: true // enable set cookie
}));

app.use(require('./routes/gridfs'));

app.use(morgan('dev'));
 
app.get('/', (req, res) => {
    res.send('BACKEND BUCKET WORKS');
});

const port = process.env.PORT || 3000;
app.listen(port, () => 
  console.log(`App is listening on port http://localhost:${port}`)
);

Explicando algo mas este index.js vemos que inicial iniciamos un servidor express le añadimos el fileupdaload y configuramos la creación de carpetas, extendemos los caracteres del bodyparse. En cuanto a lo del cors es opcional si vamos a usar postman pero si la petición que hacemos tiene como origen un navegador web tenemos que configurar el cors para que el servidor la acepte.

Luego añadimos el archivo routes con gridfs en el cual es donde configuramos las rutas de entrega y descarga de binarios.

Configurar el morgan para ver las peticiones por consola, esto es opcional.

Por ultimo ponemos a escuchar en el puerto 3000 o el que configures en la variable de entorno PORT

Lo importante del bucket esta aqui.

/routes/gridfs
const express = require('express');
const router = express.Router();
var mongoose = require('mongoose');
var streamifier = require('streamifier');
var fs = require('fs');

// DB
const mongoURI = "mongodb://localhost:27017/bucket";

// connection
const conn = mongoose.createConnection(mongoURI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

let gridfsbucket;
conn.once("open", () => {

  gridfsbucket = new mongoose.mongo.GridFSBucket(conn.db, {
    bucketName: "filesBucket"
  });
});

router.post('/uploadfile', (req, res) => {
    
    let filename = req.files.file.name;
   
    streamifier.createReadStream(req.files.file.data,).
        pipe(gridfsbucket.openUploadStream(filename,{metadata:req.body})).
        on('error', function (error) {
            assert.ifError(error);
        }).
        on('finish', function () {
            console.log('done!');
            res.status(200).json({
                success: true,
                msg: 'File Uploaded successfully..'
            });
        });
})

router.get("/files", (req, res) => {

    gridfsbucket.find().toArray((err, files) => {

      if (!files || files.length === 0) {
        return res.status(404).json({
          err: "no files exist"
        });
      }
      let beauty_files = files.map(file => {
          return file.filename
      })

      return res.json(beauty_files);
    });
  });

router.delete('/delete/:filename', (req, res) => {

  gridfsbucket.find({
      filename: req.params.filename
  })
  .toArray((err, files) => {
    if (!files || files.length === 0) {
      return res.status(404).json({
        err: "no files exist"
      });
    }
    gridfsbucket.delete(files[0]._id)
    console.log('delete file')
    res.status(200).json({
      success: true,
      msg: 'File Uploaded successfully..'
  });
  });  
});

router.get('/download/:filename', (req, res) => {

    gridfsbucket.find({
      filename: req.params.filename
    })
    .toArray((err, files) => {
      if (!files || files.length === 0) {
        return res.status(404).json({
          err: "no files exist"
        });
      }
      gridfsbucket.openDownloadStreamByName(req.params.filename).pipe(res);
    });
})
//write in disk
router.get('/write/:filename', (req, res) => {
    const filename = req.params.filename;

    gridfsbucket.openDownloadStreamByName(filename).
    pipe(fs.createWriteStream('./'+filename)).
        on('error', function (error) {
            console.log("error" + error);
            res.status(404).json({
                msg: error.message
            });
        }).
        on('finish', function () {
            console.log('done!');
            res.send('write successfully!')
        });
})

module.exports = router;

Lo primero es crear una conexión a la base de datos de mongodb y abrir el gridfs

A continuación definimos los métodos de escritura y lectura de los archivos que son:

/uploadfile

Ahora con un sencillo curl -F podemos subir archivos al servidor.

curl -F 'file=@/root/plus.png' http://localhost:3000/uploadfile

Incluso mas de 1 en la misma peticion

curl -F 'files[]=@/path/to/fileX' -F 'files[]=@/path/to/fileY' ... http://localhost:3000/upload

/download

Para descargarlo únicamente tenemos que conocer el nombre del archivo y espeficicarlo en el path

curl -X GET 'http://localhost:3000/download/plus.png' -o plus.png

/files

Y si queremos listar los archivos que contiene tenemos este método, en este ejemplo el comando find no tiene parámetros por lo que devolverá la collection al completo no usar si es muy grande. En un caso real parametrizarla.

curl -X GET 'http://localhost:3000/files'

/delete

Por supuesto tenemos que añadir un metodo para poder elimnar los archivos.

curl -X DELETE 'http://localhost:3000/delete/plus.png'

/write

Como extra añado un método de escritura en disco duro desde la base de datos, quizás sea útil como ejemplo de como se hace

curl -X GET 'http://localhost:3000/write/plus.png'

Y con esto ya tenemos un bucket sencillo. Se combina muy bien con cosas como por ejemplo vue-dropzone y se puede integrar muy fácilmente con istio. Si queréis mas ejemplos no dudéis en escribirme espero que os haya gustado.


0 comentarios

Deja una respuesta

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *