Simple Node.JS REST API call - javascript

I have a simple app that requires a REST API call to perform CRUD (Create,Read,Update,Delete). However, i can't seem to get the REST API working.
When it's executing the put operation, i'm getting
"api.js:81 Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at callAPI (api.js:81)"
I'm using Api.js to check the API calls.
api-photos.js
//photos.js
var express = require('express');
var router = express.Router();
var multer = require('multer');
var photoController = require('../../controllers/photoController');
var upload = multer({
storage: photoController.storage,
fileFilter: photoController.imageFilter
});
//import PhotoService
const PhotoService = photoController.PhotoService;
router.use((req, res, next)=>{
//set mime type for all request and origin
res.set({
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,OPTIONS',
"Access-Control-Allow-Headers":"Content-Type, Access-Control-Allow-Headers",
'Content-type':'applicaion/json'
});
if(req.method == 'OPTIONS'){
return res.status(200).end();
}
next();
})
// photos - list
router.get('/', (req, res, next)=>{
PhotoService.list()
//returns promise - argument passed photos
.then((photos)=>{
console.log(`API: Found images: ${photos}`);
res.status(200);
//set content type header to application/json - set correct mime type
res.send(JSON.stringify(photos));
});
})
// photos/:photoid - find
router.get('/:photoid', (req, res, next)=>{
PhotoService.read(req.params.photoid)
//returns promise - argument passed photos
.then((photo)=>{
console.log(`API: Found images: ${photo}`);
res.status(200);
//set content type header to application/json - set correct mime type
res.send(JSON.stringify(photo));
}).catch((err)=>{
});
});
// /photos POST create
router.post('/', upload.single('image'), async (req, res, next)=>{
var path = "/static/img/" + req.file.filename;
var photo = {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
imageurl: path,
title: req.body.title,
filename: req.file.filename,
description: req.body.description,
size: req.file.size / 1024 | 0
}
//calling on photo service to return json object
try{
const photoSave = await PhotoService.create(photo);
res.status(201);
res.send(JSON.stringify(photoSave));
}catch(err){
console.log(err);
throw new Error("PhotoSaveError", photo);
}
});
// /photos/photoid: PUT - update
router.put('/:photoid', (req, res, next)=>{
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
PhotoService.update(req.params.photoid, putdata)
console.log()
.then((updatePhoto)=>{
res.status(200);
res.send(JSON.stringify(updatedPhoto));
}).catch((err)=> {
res.status(404);
res.end();
});
});
// /photos/photoid: DELETE - delete
router.delete('/:photoid', (req, res, next)=>{
PhotoService.delete(req.params.photoid)
.then((photo) => {
console.log(`Found images: $(photo)`);
res.status(200);
res.send(JSON.stringify(photo));
}).catch((err)=> {
res.status(404);
res.end();
});;
});
module.exports = router;
photo.js
//photos.js
var express = require('express');
var router = express.Router();
var app = express();
var multer = require('multer');
var photoController = require('../controllers/photoController');
var flash = require('express-flash');
//create upload object- intialize
var upload = multer({
storage: photoController.storage,
fileFilter: photoController.imageFilter
});
//Photo model import is required
var Photo = require('../models/photoModel');
const PhotoService = photoController.PhotoService
//flash messaging
router.use(flash());
//LIST - Get request to search database for our photos
router.get('/', (req, res, next)=>{
//search the DB for the photos
PhotoService.list()
.then((photos)=>{
//call photos view
res.render('photos', {
photos : photos,
flashMsg: req.flash("fileUploadError")
});
})
.catch((err)=>{
if (err) {
res.end("ERROR!");
}
});
});
//FIND - route for getting photo Details with form for editing
router.get('/:photoid', (req, res, next)=>{
console.log("finding "+req.params.photoid);
PhotoService.read({'_id': req.params.photoid})
//return promoise then handle it to render photo
.then((photo)=>{
res.render('updatePhoto', {
photo: photo,
flashMsg: req.flash("photoFindError")
});
}).catch((err)=>{
if (err) console.log(err);
});
});
//DELETE - route for deleting the photos
router.delete('/delete/:photoid', function(req, res){
PhotoService.delete({'_id': req.params.photoid})
.then((photos) => {
res.redirect('/photos');
});
});
//UPDATE - route for posting newly updated details
router.post('/:photoid', (req, res, next)=>{
PhotoService.update({'_id': req.params.photoid})
//return promoise then set photo data details
.then((photo)=>{
var data = {
title: req.body.title,
description: req.body.description
}
//set the data, save the photo details and redirect to photo list
photo.set(data);
photo.save().then(()=>{
res.redirect('/photos');
});
})
.catch((err)=>{
if (err) console.log(err);
});
});
//CREATE - post fields to the server and save them
router.post('/', upload.single('image'), (req, res, next)=>{
var path = "/static/img/" + req.file.filename;
var photo = {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
imageurl: path,
title: req.body.title,
filename: req.file.filename,
description: req.body.description,
size: req.file.size / 1024 | 0
}
//Saving photo to DB
var photo = new Photo(photo);
photo.save()
.then(()=>{
//redirect after save, if succesfull
res.redirect('/photos');
})
//Catch error logs error
.catch((err)=>{
if (err){
console.log(err);
throw new Error("PhotoSaveError", photo);
}
});
});
//function will get called if above gets unhandled error - flash to display image and redirect
router.use(function(err, req, res, next){
console.error(err.stack);
if (err.message == "OnlyImageFilesAllowed"){
req.flash('fileUploadError', "Please select an image file with jpg, png, or gif")
res.redirect('/photos');
//2nd condition error if there was a problem saving
} else if (err.message == "PhotoSaveError"){
req.flash('photoSaveError', "There was a problem saving the photo")
res.redirect('/photos');
} else{
next(err);
}
});
//export the module
module.exports = router;
api.js
// wrap in IIFE to control scope
(function(){
const baseURL = 'http://localhost:8080';
function testAPIs(){
// test list first
var testId = '';
var testJSON = {};
// list
callAPI('GET', '/api/photos', null, null)
.then((list)=>{
console.log('\n\n***************************\nlist results:');
console.log(list);
testId = list[0]._id;
// create
let input = document.querySelector('input[type="file"]')
let data = new FormData()
data.append('image', input.files[0]);
data.append('title', 'My API Test Title');
data.append('description','This is an AJAX API test');
callAPI('POST', '/api/photos', null, data)
.then((photo)=>{
photoId = photo._id;
savedPhoto = photo; // keep a handle to the created photo object
console.log('\n\n***************************\ncreate results:');
console.log(photo);
// find
callAPI('GET','/api/photos/'+photoId, null, null)
.then((photo)=>{
console.log('\n\n***************************\nfind results:');
console.log(photo);
// update
testJSON.description += ' appended by the AJAX API ';
callAPI('PUT','/api/photos/'+photoId, null, savedPhoto)
.then((photo)=>{
console.log('\n\n***************************\nupdate results:');
console.log(photo);
//delete
callAPI('DELETE', '/api/photos/'+photoId, null, null)
.then((result)=>{
console.log('\n\n***************************\ndelete result:');
console.log(result);
})
});
});
});
})
.catch((err)=>{
console.error(err);
});
}
async function callAPI(method, uri, params, body){
jsonMimeType = {
'Content-type':'application/json'
}
try{
/* Set up our fetch.
* 'body' to be included only when method is POST
* If 'PUT', we need to be sure the mimetype is set to json
* (so bodyparser.json() will deal with it) and the body
* will need to be stringified.
* '...' syntax is the ES6 spread operator.
* It assigns new properties to an object, and in this case
* lets us use a conditional to create, or not create, a property
* on the object. (an empty 'body' property will cause an error
* on a GET request!)
*/
var response = await fetch(baseURL + uri, {
method: method, // GET, POST, PUT, DELETE, etc.
...(method=='POST' ? {body: body} : {}),
...(method=='PUT' ? {headers: jsonMimeType, body:JSON.stringify(body)} : {})
});
return response.json(); // parses response to JSON
}catch(err){
console.error(err);
return "{'status':'error'}";
}
}
// Calls our test function when we click the button
// afer validating that there's a file selected.
document.querySelector('#testme').addEventListener("click", ()=>{
let input = document.querySelector('input[type="file"]')
if (input.value){
testAPIs();
}else{
alert("please select an image file first");
}
});
})();

Here is an update PUT handler which should stop throwing "undefined .then of ...", note that updatePhoto needed to be renamed to updatedPhoto as well.
router.put('/:photoid', (req, res, next) => {
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
PhotoService.update(req.params.photoid, putdata).then((updatedPhoto) => {
res.status(200);
res.send(JSON.stringify(updatedPhoto));
}).catch((err) => {
res.status(404);
res.end();
});
});
And if you are using node 8+ you can use async/await. It simplifies the code and makes the problems easier to see:
router.put('/:photoid', async (req, res, next) => {
try {
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
const updatedPhoto = await PhotoService.update(req.params.photoid, putdata);
res.status(200);
res.send(JSON.stringify(updatedPhoto));
} catch (e) {
res.status(404);
res.end();
}
});

Related

Express.js application error: Cannot read properties of undefined (reading 'transfer-encoding'

I am working on a blogging app API with express and MongoDB.
I am trying to add a post image for every blog post. Being new to express, I ran into this problem.
And i got this error:
Cannot read properties of undefined (reading 'transfer-encoding'
Here is the post controller code code:
const asyncHandler = require("express-async-handler");
const imageModel = require("../models/imageModel");
const User = require("../models/userModel");
const Post = require("../models/postModel");
// storage
const Storage = multer.diskStorage({
destination: "storage",
filename: (res, req, file, cb) => {
cb(null, Date.now() + file.originalname);
},
});
const upload = multer({
storage: Storage,
}).single("img");
// #desc Create a new post
// #route POST /api/posts/
// #access Private
const createPost = asyncHandler(async (res, req) => {
let img;
upload(req, res, async function (err) {
if (err) {
res.status(400);
throw new Error("Error uploading images.");
}
const newImage = await new imageModel({
img: {
data: req.file.filename,
contentType: "image/png",
},
});
newImage.save().then(console.log("Successfully uploaded"));
img = newImage;
});
console.log(img);
const { title, description, categories, nacCompatible, downloadURL } =
req.body;
if (!title || !description || !categories || !downloadURL) {
res.status(400);
throw new Error("Please add all the required fields.");
}
// Get user using the id in the JWT
const user = await User.findById(req.user.id);
if (!user) {
res.status(401);
throw new Error("User not found");
}
const post = await Post.create({
title,
description,
img,
categories,
nacCompatible,
downloadURL,
user: req.user._id,
status: "new",
});
res.status(201).json(post);
});
I also have const multer = require("multer"); at the top of the controller.
The create post function worked fine until I tried to add this upload image feature.
This line: "createPost = asyncHandler(async (res, req)"
You put the req and res in the wrong order

Stripe & Node.js - "Cannot POST /create-checkout-session"

I'm trying to follow the Stripe Checkout subscription instructions:
https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=checkout
When I submit the form, over localhost I get "Cannot POST /create-checkout-session" (404 in network tab), and if I run from my production server, it just opens /create-checkout-session as a new (blank) Vue page. I have tried changing the form action to https://mydomain.xyz/create-checkout-session, but it didn't work.
Subscribe.vue
<form action="/create-checkout-session" method="POST">
<input type="hidden" name="priceId" value="[removed for Stack Overflow]" />
<button type="submit">Checkout</button>
</form>
I don't know if something is interfering with the endpoint, so I've copied my entire app.js file:
app.js
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = require('stripe')('[removed for StackOverflow]');
//connect mongoDB
mongoose.Promise = global.Promise;
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database couldn't be connected to: " + error);
}
)
const cryptoEndPoint = require('../backend/routes/crypto.route')
const app = express();
app.use(decodeIDToken);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors())
//API
app.use('/api', cryptoEndPoint)
app.post("/create-checkout-session", async (req, res) => {
console.log("can't even get anything to console log, only get createError is not defined");
const { priceId } = req.body;
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [customer_email] - lets you prefill the email input in the form
// [automatic_tax] - to automatically calculate sales tax, VAT and GST in the checkout page
// For full details see https://stripe.com/docs/api/checkout/sessions/create
try {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: priceId,
// For metered billing, do not pass quantity
quantity: 1,
},
],
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
// the actual Session ID is returned in the query parameter when your customer
// is redirected to the success page.
success_url: 'https://mydomain.xyz/thankyou?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://mydomain.xyz/thankyou',
});
return res.redirect(303, session.url);
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
//create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port);
})
//Find 404
app.use((req, res, next) => {
next(createError(404));
})
//error handler
app.use(function (err, req, res, next) {
console.log(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
})
/**
* Decodes the JSON Web Token sent via the frontend app
* Makes the currentUser (firebase) data available on the body.
*/
async function decodeIDToken(req, res, next) {
if (req.headers?.authorization?.startsWith('Bearer ')) {
const idToken = req.headers.authorization.split('Bearer ')[1];
// console.log(idToken);
try {
const decodedToken = await admin.auth().verifyIdToken(idToken);
// console.log("one");
req['currentUser'] = decodedToken;
// console.log("two");
} catch (err) {
console.log("error: " + err);
}
}
next();
}
app.post("/webhook", async (req, res) => {
let data;
let eventType;
// Check if webhook signing is configured.
const webhookSecret = '[removed for Stack Overflow]'
if (webhookSecret) {
// Retrieve the event by verifying the signature using the raw body and secret.
let event;
let signature = req.headers["stripe-signature"];
try {
event = stripe.webhooks.constructEvent(
req.body,
signature,
webhookSecret
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`);
return res.sendStatus(400);
}
// Extract the object from the event.
data = event.data;
eventType = event.type;
} else {
// Webhook signing is recommended, but if the secret is not configured in `config.js`,
// retrieve the event data directly from the request body.
data = req.body.data;
eventType = req.body.type;
}
switch (eventType) {
case 'checkout.session.completed':
//...
break;
case 'invoice.paid':
//...
break;
case 'invoice.payment_failed':
//...
break;
default:
// Unhandled event type
}
res.sendStatus(200);
});
Does anyone know what is going wrong?
I added this to my app.js file, and it's working:
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.use(allowCrossDomain);

How come fetch only works here when I add an alert to the end of the line? Express + NodeJS + Fetch. What's a good fix here

I'm using NodeJS w/ Express to create a web app that records your audio using the VMSG library and posts the BLOB audio to my file system using HTTP Requests and multer. It also adds that instance of a recording into a MongoDB database.
I'm having an issue with the fetch command. It's not working unless I put an alert right after the fetch. The way I have it set up is that I have my main express app (index.js), and a router to the /recordingsDirectory (recordings.js) which is the endpoint for processing the posts. My main index HTML page uses Handlebars and uses a separate JS script (recorder.js) to 1) use the VMSG library and 2) fetch a POST to the /recordingsDirectory once someone submits the audio file w/ the name and the AudioBlob present. This is where I'm stuck. I can fetch in recorder.js with an alert line after the fetch, but I can't have the fetch on the end of the else if block by itself. I'd like to do it without this since the alert is ugly. A solution I've tried is that I tried to make the onsubmit function async and await fetch since I thought maybe it's waiting for a promise but that didn't work.
Here are the files. I commented CRITICAL and SUPER CRITICAL to the lines of code that you should check out and I think where the issues lie:
index.js
const express = require('express')
const handlebars = require('express-handlebars')
const path = require('path')
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const xhr = new XMLHttpRequest()
const db = require('./db')
const app = express()
const PORT = process.env.PORT || 8000
app.set('view engine', 'hbs')
app.engine('hbs', handlebars({
layoutsDir: path.join(__dirname, 'views', 'layouts'),
extname: 'hbs',
defaultLayout: 'index',
partialsDir: path.join(__dirname, 'views', 'partials'),
}))
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
return res.status(400).send({ status: 404, message: err.message })
}
next()
})
app.get('/', (req, res) => {
res.render('main', {
title: 'Main Page'
})
})
app.get('/recordings', (req, res) => {
var database = db.get().db('AudioJungle')
database.collection('recordings').find().sort({ "date": -1 }).toArray(function(err, docs) {
res.render('recordings', {
title: 'Recordings',
recordings: docs
})
})
})
// CRITICAL
app.use('/recordingsDirectory', require('./recordings/recordings'))
app.use(express.static('public'))
app.use('/scripts', express.static(path.join(__dirname, 'node_modules', 'vmsg')))
db.connect(function(err) {
if (err) {
console.log('Unable to connect to Mongo.')
process.exit(1)
} else {
app.listen(PORT, () => console.log(`Listening on Port: ${PORT}`))
}
})
process.on('SIGINT', function() {
db.close(function () {
console.log('Disconnected on app termination');
process.exit(0);
});
});
app.use((req, res, next) => {
res.status(404).send({
status: 404,
error: 'Not found'
})
})
recordings.js (Aka the /recordingsDirectory endpoint for a fetch POST)
const express = require('express')
const router = express.Router()
const multer = require('multer')
const fs = require('fs-extra')
const db = require('../db')
const { ObjectId } = require('bson')
const moment = require('moment')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, callback) => {
let path = './public/uploads'
fs.mkdirsSync(path)
callback(null, path)
},
filename: (req, file, callback) => {
createRecording(req).then((id) => {
var file_name = id + '.mp3'
callback(null, file_name)
})
}
})
})
var type = upload.single('audio-file')
// CRITICAL
router.post('/', type, (req, res) => {
console.log('made it')
res.status(200)
res.send('OK')
})
router.delete('/delete', (req, res) => {
deleteRecording(req.body._id).then((dbResponse) => {
if (dbResponse == null || dbResponse == undefined) {
res.status(400).json({ msg: 'ID already deleted' })
} else {
res.status(200)
}
})
})
router.get('/', (req, res) => {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
recordings.findOne({"_id": ObjectId(req.query.id)}, function(err, result) {
if (err) throw err
if (result == null || result == undefined) {
return res.status(400).json({
status: 404,
error: 'Recording no longer in the database'
})
}
res.status(200)
res.json({
name: result.name,
date: result.date
})
})
})
async function createRecording(req) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioObject = {
name: req.body.name,
date: moment().format('MMMM Do YYYY, h:mm:ss a')
}
var dbResponse = await recordings.insertOne(audioObject)
return dbResponse.insertedId
}
async function deleteRecording(id) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioToDelete = {
_id: ObjectId(id)
}
var deleteResult = await recordings.deleteOne(audioToDelete)
return deleteResult
}
module.exports = router
And below is the Script the audio and name and tries to Fetch (where I need the alert for it to actually process into the /recordingsdirectory)
recorder.js
import { record } from "/scripts/vmsg.js";
let recordButton = document.getElementById("record");
var blobObj = null
recordButton.onclick = function() {
record({wasmURL: "/scripts/vmsg.wasm"}).then(blob => {
blobObj = blob
var tag = document.createElement("p")
tag.id="finishedRecording"
var text = document.createTextNode("Audio File Recorded")
tag.appendChild(text)
var element = document.getElementById("box")
element.appendChild(tag)
document.getElementById('box').appendChild(a)
})
}
let form = document.getElementById('mp3Form');
form.addEventListener("submit", submitAudio)
function submitAudio() {
var fileName = form.elements[0].value
if (fileName == "") {
alert('Please enter a name for your file')
} else if (blobObj != null) {
// CRITICAL
// SUPER CRITICAL WHERE FETCH DOESN'T WORK UNLESS I PUT AN ALERT AT THE END
const formData = new FormData()
formData.append('name', fileName)
formData.append('audio-file', blobObj)
const options = {
method: 'POST',
body: formData
}
fetch('/recordingsDirectory', options);
// If I comment an alert here, /recordingsDirectory will process the post since it console.logs 'made it'
} else {
alert('Record some Audio to upload')
}
}
Here's my file system.
Also, I'd like to mention that the fetch works properly on my Windows PC without having to add the alert, but it doesn't work without the alert on my macbook. If any one figures out a fix or an error in how I'm doing things to allow this please let me know. I've been stuck on this problem for a day now. Thanks a bunch!

Passing a pdf file to a function when it requires a path or link

I am working on a web application for an online library. I want to extract metadata from the PDF's that will be uploaded and for that I am using the nodejs library pdf.js-extract and multer-gridfs-storage for the upload. The problem is that I am receiving a PDF file (req.file) and the function requires a path or link to the PDF file and therefore shows the error
"TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type object"
I would like to know if there is a way to pass a file as a link, save the file locally temporarily or find another library that fits my needs.
This is my current code.
const PDFExtract = require('pdf.js-extract').PDFExtract;
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
pdfExtract.extract(req.file, options, (err, data) => {
if (err){
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
});
(Edit for clarification) I am using multer with gridFS to upload a file to mongoose.
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
// Create storage engine
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString('hex') + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: 'uploads'
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
Solution inspired by Oliver Nybo
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
var readableStream = gfs.createReadStream({ filename : req.file.filename });
var buff;
var bufferArray = [];
readableStream.on('data',function(chunk){
bufferArray.push(chunk);
});
readableStream.on('end',function(){
var buffer = Buffer.concat(bufferArray);
buff=buffer;
pdfExtract.extractBuffer(buff, options, (err, data) => {
if (err) {
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
})
});
According to multer's api documentation, you can use req.file.path to get the full path of the uploaded file.
const PDFExtract = require('pdf.js-extract').PDFExtract;
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
pdfExtract.extract(req.file.path, options, (err, data) => {
if (err){
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
});
Edit: I just read the multer options and there is an option called preservePath.
preservePath - Keep the full path of files instead of just the base name
Edit 2: I think you need to extract the file from the database with gridfs-stream, then convert it into a buffer (like in this thread), and then use PDFExtract's extractBuffer function.

Image upload isn't working using multer

I setup multer like this
let multer = require('multer');
let apiRoutes = express.Router();
let UPLOAD_PATH = '../uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, UPLOAD_PATH);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now());
}
});
let upload = multer({ storage: storage });
and in route I am getting data and an image and use multer like!
apiRoutes.post('/update', passport.authenticate('jwt', { session: false }), (request, response) => {
let record = {
name: request.body.name,
location: request.body.location,
about: request.body.about,
userid: request.body.userid,
avatar: request.body.filename
};
let userData = {
name: request.body.name
};
if (request.body.filename) {
upload(request, response, (error) => {
});
}
profile.findOneAndUpdate({ userid: request.body.userid }, record, {new: true}, (error, doc) => {
if (error) response.json(error);
user.findOneAndUpdate({ _id: request.body.userid }, record, (error, result) => {
if (error) throw error;
response.json(doc);
});
});
});
What is happening with this code is that when I do not send an image to backend then I get data from front end and store it into database. But when I send image along side data then it return POST /api/1.0/profile/update 401 0.396 ms - -.
It means I am not getting any data at all. Whats wring with the code here?
You can't use Multer in your /update route. Use Multer in your router like this:
var upload = multer({ dest: 'uploads/' })
apiRoutes.post('/profile', upload.single('image'), function (req, res, next) {
// Uploaaded
})
if you add it and still can't get our file, you should update your form with this parameter: enctype="multipart/form-data"

Categories