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