I followed this tutorial on file upload with multer-express and then retrieving image by id Scoth.io.
The setup uses LokiJS as database.
All the API's works fine however when API to retrieve multiple images by ID isn't working for multiple images. Most of get requests are pending on server (status is pending in Network panel of Chrome Dev tools).
The requests never gets completed once in pending state (forever pending) and server gets stuck in that.
app.get('/images/:id', async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db);
const result = col.get(req.params.id);
if (!result) {
res.sendStatus(404);
return;
};
res.setHeader('Content-Type', result.mimetype);
fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res);
} catch (err) {
res.sendStatus(400);
}
})
import * as express from 'express'
import * as multer from 'multer'
import * as cors from 'cors'
import * as fs from 'fs'
import * as path from 'path'
import * as Loki from 'lokijs'
import { loadCollection, imageFilter } from './utils'
//setup
const DB_NAME = 'db.json'
const COLLECTION_NAME = 'images'
const UPLOAD_PATH = 'uploads'
const upload = multer({ dest: `${UPLOAD_PATH}/`, fileFilter: imageFilter }) //MULTER CONFIG
const db = new Loki(`${UPLOAD_PATH}/${DB_NAME}`, { persistenceMethod: 'fs' })
// app
const app = express();
app.use(cors());
app.get('/', (req, res) => {
res.json({responseText : 'Server running successfully'})
})
//Upload Single
app.post('/fileUpload', upload.single('file'), async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
const data = col.insert(req.file)
db.saveDatabase()
res.send({id: data.$loki, fileName: data.filename, originalName: data.originalname })
} catch (err) {
res.sendStatus(400)
}
})
//Upload Multiple
app.post('/photos/upload', upload.array('photos', 12), async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
const data = [].concat(col.insert(req.files))
db.saveDatabase()
res.send(data.map(x => ({ id: x.$loki, fileName: x.filename, originalName: x.originalname })));
} catch (err) {
res.sendStatus(400)
}
})
//Retrieve Image
app.get('/images', async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
res.send(col.data)
} catch(err) {
res.sendStatus(400)
}
})
// Retrieve Image by Id
app.get('/images/:id', async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
const result = col.get(parseInt(req.params.id))
if(!result) {
res.sendStatus(404)
return;
}
res.setHeader('Content-Type', result.mimetype);
fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res)
} catch(err) {
res.sendStatus(400)
}
})
app.listen(3000, function () {
console.log('listening on port 3000!');
})
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fetch Image (NodeJS-LokiJS API) - Example</title>
<style>
.photo {
width: 100px;
display: block;
margin-bottom: 5px;
border: 2px solid black;
}
</style>
</head>
<body>
<h1>HTML Example</h1>
<p>
JPEG:<br>
<img class="photo" src="http://localhost:3000/images/1">
<img class="photo" src="http://localhost:3000/images/2">
<img class="photo" src="http://localhost:3000/images/3">
<img class="photo" src="http://localhost:3000/images/4">
<img class="photo" src="http://localhost:3000/images/5">
<img class="photo" src="http://localhost:3000/images/6">
</p>
</body>
</html>
import * as del from 'del'
import * as Loki from 'lokijs'
const loadCollection = function (colName, db: Loki): Promise<Loki.Collection<any>> {
return new Promise(resolve => {
db.loadDatabase({}, _=> {
const _collection = db.getCollection(colName) || db.addCollection(colName)
resolve(_collection)
})
})
}
const imageFilter = function (req, file, cb) {
// accept image only
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
}
export { imageFilter, loadCollection }
Looks like there is a problem with loadCollection
indeed.
Remove db.loadDatabase
from loadCollection
and load your db only once, in index.ts after you initialised it.
index.ts
import * as express from 'express'
import * as multer from 'multer'
import * as cors from 'cors'
import * as fs from 'fs'
import * as path from 'path'
import * as Loki from 'lokijs'
import { loadCollection, imageFilter } from './utils'
//setup
const DB_NAME = 'db.json'
const COLLECTION_NAME = 'images'
const UPLOAD_PATH = 'uploads'
const upload = multer({ dest: `${UPLOAD_PATH}/`, fileFilter: imageFilter }) //MULTER CONFIG
const db = new Loki(`${UPLOAD_PATH}/${DB_NAME}`, { persistenceMethod: 'fs' })
db.loadDatabase({});
// app
const app = express();
app.use(cors());
app.get('/', (req, res) => {
res.json({responseText : 'Server running successfully'})
})
//Upload Single
app.post('/fileUpload', upload.single('file'), async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
const data = col.insert(req.file)
db.saveDatabase()
res.send({id: data.$loki, fileName: data.filename, originalName: data.originalname })
} catch (err) {
res.sendStatus(400)
}
})
//Upload Multiple
app.post('/photos/upload', upload.array('photos', 12), async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
const data = [].concat(col.insert(req.files))
db.saveDatabase()
res.send(data.map(x => ({ id: x.$loki, fileName: x.filename, originalName: x.originalname })));
} catch (err) {
res.sendStatus(400)
}
})
//Retrieve Image
app.get('/images', async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
res.send(col.data)
} catch(err) {
res.sendStatus(400)
}
})
// Retrieve Image by Id
app.get('/images/:id', async (req, res) => {
try {
const col = await loadCollection(COLLECTION_NAME, db)
const result = col.get(parseInt(req.params.id))
if(!result) {
res.sendStatus(404)
return;
}
res.setHeader('Content-Type', result.mimetype);
fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res)
} catch(err) {
res.sendStatus(400)
}
})
app.listen(3000, function () {
console.log('listening on port 3000!');
})
utils.ts
import * as del from 'del'
import * as Loki from 'lokijs'
const loadCollection = function (colName, db: Loki): Promise<Loki.Collection<any>> {
return new Promise(resolve => {
const _collection = db.getCollection(colName) || db.addCollection(colName)
resolve(_collection)
})
}
const imageFilter = function (req, file, cb) {
// accept image only
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
}
export { imageFilter, loadCollection }