issues using base64 with showing image on client side - javascript

I am trying to upload an image and show it on the client side using base 64. I am successful in sending to mongodb but not in showing the image once it is uploaded.
My theory: I need to have the setDefaultImage function outside the setGetBaseFile function to fix to be able to see image on client side.
when I attempt to move it I get a "Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. The only way arround this error that I have found is to move the function back in the parent function.
Below is my code for image.js
const mongoose = require("mongoose");
const Image = mongoose.model("gallery");
const express = require('express');
const ImageRouter = express.Router();
const DIR = './public/';
/* upload image in base64 format, thereby, directly storing it in mongodb datanase
along with images uploaded using firebase storage */
ImageRouter.route("/uploadbase")
.post((req, res, next) => {
const newImage = new Image({
imageName: req.body.imageName,
imageData: req.body.imageData
});
newImage.save()
.then((result) => {
res.status(200).json({
success: true,
document: result
});
})
.catch((err) => next(err));
});
module.exports = ImageRouter;
Below is my client side code:
import React, { useState } from "react";
import Container from "react-bootstrap/Container";
import Card from "react-bootstrap/Card";
// import Button from "react-bootstrap/Button";
// import "./postverse.css";
import Form from "react-bootstrap/Form";
import axios from "axios";
import FileBase from 'react-file-base64';
import DefaultImg from '../../assets/default-image.jpg';
const GlobalPost = () => {
const API_URL = "http://localhost:5000";
const [baseImage, UseBaseImage] = useState(DefaultImg);
const [DefaultImage, setDefaultImage] = useState("");
// function to upload image once it has been captured
setDefaultImage({
baseImage: DefaultImg
});
// function to capture base64 format of an image
function setGetBaseFile(files) {
// create a local readable base64 instance of an image
UseBaseImage({
baseImage: files.base64
});
let imageObj = {
imageName: "base-image-" + Date.now(),
imageData: files.base64.toString()
};
axios.post(`${API_URL}/image/uploadbase`, imageObj)
.then((data) => {
if (data.data.success) {
alert("Image has been successfully uploaded using base64 format");
UseBaseImage("base")
}
})
.catch((err) => {
alert("Error while uploading image using base64 format")
UseBaseImage("base")
});
}
return (
<div className="globalpost">
<Container className="mt-5 ml-auto mr-auto">
<h1 className="text-center">
Post to
<span className="text-success"> ShareVerse</span>
</h1>
<Form
className="shadow p-3 mb-5 bg-white rounded"
action="/search"
method="post"
encType="multipart/form-data"
>
<Form.Group controlId="formBasicVerse">
<Form.Label><h5>Upload Image</h5></Form.Label>
<FileBase type="file"
multiple={false}
onDone={setGetBaseFile}
/>
<Card.Img src={baseImage} alt="upload-image"></Card.Img>
</Form.Group>
</Form>
</Container>
</div>
);
};
export default GlobalPost;
Below is my mongoose data.schema
const mongoose = require("mongoose");
//create schema
const ImagesSchema = new mongoose.Schema({
name: {
type: String,
default: "none",
required: true
},
imageData: {
// type: mongoose.Types.ObjectId,
type: String,
required: true,
},
});
module.exports = mongoose.model("gallery", ImagesSchema);
Below is my app.js
// file includes all app level config, middleware, and supporting libraries
const express = require("express"); //import express
const app = express(); //initalise app with express
const cors = require("cors");
const bodyParser = require("body-parser");
const logger = require("morgan");
const routes = require("./routes/DataRoutes");
const ImageRouter = require('./routes/image');
app.use(bodyParser.json());
//body-parser handles HTTP POST requests.
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//enable Cross-Origin Resource Sharing.
app.use(cors());
app.use(express.json());
// get log details of our app if needed
app.use(logger("dev"));
//middleware to import routes
app.use('/image', ImageRouter);
app.use("/", routes);
app.use('/search', express.static('search'));
module.exports = app;

Related

Cannot get file uploaded from react js frontend to express backend

//This is frontend
import React, { useState } from "react";
import axios from "axios";
import "./App.css";
const App = () => {
const [logFile, setLogFile] = useState<File | null>(null);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setLogFile(e.target.files![0]);
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const formData = new FormData();
formData.append("logFile", logFile!);
console.log(formData);
const response = await axios.post(
"http://localhost:3001/logs",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
console.log(response.data);
} catch (error) {
console.error(error);
}
};
return (
<>
<div className="App">
<h1>Upload file</h1>
<form onSubmit={handleSubmit}>
<div>
<input type="file" onChange={handleChange} />
</div>
<button type="submit">Submit</button>
</form>
</div>
</>
);
};
export default App;
//This is backend
const express = require('express');
const app = express();
const port = 3001;
const winston = require('winston');
const cors = require("cors")
app.use(cors())
const logger = winston.createLogger({
transports: [
new winston.transports.File({
level: 'error',
filename: 'error.log',
handleExceptions: true,
json: true,
maxsize: 5242880,
maxFiles: 5,
colorize: false
}),
new winston.transports.File({
level: 'warn',
filename: 'warning.log',
handleExceptions: true,
json: true,
maxsize: 5242880,
maxFiles: 5,
colorize: false
})
],
exitOnError: false
});
app.use(express.json());
app.get("/", (req, res) => {
res.json({ "message": req.body.logFile })
})
app.post('/logs', (req, res) => {
const logFile = req.body.logFile;
const errorLogs = [];
const warnLogs = [];
// Log error and warn messages to separate files
logFile?.forEach(log => {
if (log.level === 'error') {
logger.error(log);
errorLogs.push(log);
} else if (log.level === 'warn') {
logger.warn(log);
warnLogs.push(log);
}
});
res.json({ errorLogs, warnLogs });
});
app.listen(port, () => {
console.log(`Server is listening at http://localhost:${port}`);
});
I'm building a log parser to log error and warn levels using react js to upload file and return filtered data as json from express server. But I'm getting empty object for formData but logfile is showing uploaded fie in console in my react js frontend
I want to send a log file from frontend to backend and return filtered json data from backend to frontend
One issue with your code is that the form element doesn't have an onSubmit event, so the form is never submitted. To fix this, you can wrap your input element and submit button in a form element and add an onSubmit event that calls the handleSubmit function.
Another issue is that you're using the fetch API to make the POST request, which may not work correctly with a multipart/form-data content type. You can use the Axios library instead, which makes it easier to send binary data in the request body.
import React, { useState } from "react";
import axios from "axios";
import "./App.css";
const App = () => {
const [logFile, setLogFile] = useState<File | null>(null);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setLogFile(e.target.files![0]);
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const formData = new FormData();
formData.append("logFile", logFile!);
const response = await axios.post("http://localhost:3001/logs", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
console.log(response.data);
} catch (error) {
console.error(error);
}
};
return (
<>
<div className="App">
<h1>Upload file</h1>
<form onSubmit={handleSubmit}>
<div>
<input type="file" onChange={handleChange} />
</div>
<button type="submit">Submit</button>
</form>
</div>
</>
);
};
export default App;
Edit:
The problem is that you are using req.body.logFile to access the uploaded file, but the file is being sent as a multipart/form-data request, not as a JSON request. You need to use a middleware that can handle multipart/form-data requests and extract the file.
To handle multipart/form-data requests in an Express application, you can use the multer middleware. Here is an example of how you can use it to extract the file from the request:
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage });
app.post('/logs', upload.single('logFile'), (req, res) => {
const logFile = req.file;
...
});
In this example, the upload.single('logFile') will extract the file from the logFile field of the multipart/form-data request and store it in memory as a Buffer. You can then access the file using req.file

Axios Post Body Empty with Express

I'm trying to send over two pieces of text data from my React frontend to an Express backend but whenever I do the post command with Axios the body appears as {} in the backend and I cannot use it. My code is listed below.
Client (App.js):
import { useState, useEffect } from 'react';
import React from 'react'
import './App.css';
import Axios from 'axios'
function App() {
const [cocktailName, setCocktailName] = useState("");
const [cocktailMain, setCocktailMain] = useState("");
const submitRecipe = () => {
const recipeData = {"cocktailName": cocktailName, "cocktailMain": cocktailMain};
Axios.post('http://localhost:3001/api/insert', recipeData).then(() => {alert('successful insert');});
}
return (
<div className="App">
<h1>CRUD Application Test</h1>
<div className='InputForm'>
<label> Cocktail Name: </label>
<input type="text" name="Cocktail Name" onChange={(e)=>
{setCocktailName(e.target.value);}}/>
<br></br>
<label> Cocktail Main Ingredient: </label>
<input type="text" name="Cocktail Main Ingredient" onChange={(e)=> {
setCocktailMain(e.target.value)}}/>
<br></br>
<button onClick={submitRecipe}>Submit</button>
</div>
</div>
);
}
export default App;
Server (App.js):
const app = express()
const mysql = require('mysql')
const bodyParser = require('body-parser')
const cors = require('cors')
const db = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'cruddatabase'
});
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.post('/api/insert', (req, res)=> {
console.log(req.body)
const cocktailName = req.body.cocktailName;
const cocktailMain = req.body.cocktailMain;
console.log(cocktailName)
console.log(cocktailMain)
//This is where i'll eventually insert it into a database
const sqlInsert = "INSERT INTO cocktail_recipes (cocktailName, cocktailMain) VALUES (?,?)"
// db.query(sqlInsert, [cocktailName, cocktailMain], (err, result) => {
// console.log(err)
// });
});
app.listen(3001, () => {
console.log("running on port 3001")
});
Any help at all is greatly appreciated.
Change this line:
app.use(bodyParser.urlencoded({extended: true}));
With this one:
app.use(express.json());
Axios send a JSON when you give an object as data without specifying the Content-Type like you did. So urlencoded is not the right set here.
you need to have a res.send() somewhere within this block
app.post('/api/insert', (req, res)=> {
console.log(req.body)
const cocktailName = req.body.cocktailName;
const cocktailMain = req.body.cocktailMain;
console.log(cocktailName)
console.log(cocktailMain)
//This is where i'll eventually insert it into a database
const sqlInsert = "INSERT INTO cocktail_recipes (cocktailName, cocktailMain) VALUES (?,?)"
// db.query(sqlInsert, [cocktailName, cocktailMain], (err, result) => {
// console.log(err)
// });
});
Firstly to get a response from your backend, you need to specify what to receive by yourself, you can send the response as json by doing: res.json("..."). You should change the ... to any response you want to get back. And if you want to get your data back, you can put it there. You can also do res.send("...") to send a message after the request was completed
Secondly, you need to let your backend accept json data by adding this after the app variable.
app.use(express.json());
Lastly, I would encourage you to you async function to make your code looks cleaner. You can change your post request code to something like this and let me know if it works.
app.post("/api/insert", async (req, res) => {
try {
const { cocktailName, cocktailMain } = req.body;
const sqlInsert = await "INSERT INTO cocktail_recipes (cocktailName, cocktailMain) VALUES (?,?)";
} catch (e) {
console.log(e.message);
}
});

Why does my Heroku-deployed React Application only work on Google Chrome?

I am currently having an issue with my React Application not working on any other browser other than Chrome. The Javascript loads just fine with no errors on Chrome and the application is currently fully deployed on Heroku (link: https://weathrd.herokuapp.com/).
In regards to my application, I have a search query set up in the "overview.js" component that creates a "get" request, with a parameter passed in that gets fed into the weather api I am using. Then, I retrieve the json information from the "/forecast" page and feed that back into "overview.js" to display on the screen.
I do not have any regex notation within any of my code, so I don't think that would be an issue here. I also have fully updated my Heroku deploy code and I do not think there is some sort of confusion on Heroku? Regardless, here is my server code, overview component code, and the error I am receiving on Safari:
server code:
const PORT = process.env.PORT || 8000;
const path = require('path');
const express = require('express');
const cors = require('cors');
const axios = require('axios');
require('dotenv').config();
const app = express();
app.use(cors());
app.use(express.static("public"))
app.get('/', (req, res) => {
res.json('hi');
});
app.get('/forecast', (req, res) => {
const options = {
method: 'GET',
url: `http://api.weatherapi.com/v1/forecast.json?`,
params: {
q: req.query.city,
key : process.env.REACT_APP_API_KEY,
days: '3',
api: 'no',
alerts: 'no',
},
};
axios.request(options).then((response) => {
res.json(response.data);
}).catch((error) => {
console.log(error);
});
});
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT} `))
Safari Error:
The error also mentions the component from which I am making the API request from "overview.js", so here is that code also:
overview.js
import React, {useState} from 'react';
import './overview.css';
import { RecentSearches } from '../Recent Searches/recentSearches';
import { Hourly } from '../Hourly/hourly';
import { Fiveday } from '../5 Day Forecast/fiveday';
import 'animate.css';
const axios = require('axios');
export function Overview() {
const [forecast, setForecast] = useState(null);
// this callback function receives the searched city entered from recentSearches and applies it to fetchForecast
const getSearch = (searchedCity) => {
fetchForecast(searchedCity);
};
async function fetchForecast(searchedCity) {
const options = {
method: 'GET',
url: 'https://weathrd.herokuapp.com/forecast',
params: {city: searchedCity}
};
axios.request(options).then((response) => {
console.log(response.data);
setForecast(response.data);
}).catch((error) => {
console.log(error);
})
};
return (
<div>
<div className='jumbotron' id='heading-title'>
<h1>Welcome to <strong>Weathered</strong>!</h1>
<h3>A Simple Weather Dashboard </h3>
</div>
<div className='container-fluid' id='homepage-skeleton'>
<div className='d-flex' id='center-page'>
<RecentSearches getSearch={getSearch}/>
<Hourly forecast={forecast}/>
</div>
</div>
<Fiveday forecast={forecast}/>
</div>
)
};
Thanks for any assistance!

Is there a way I can pass the result of a route as a field in another route?

I am trying to upload an image with multer to cloudinary and then store the resulting url in a database column. I have the following code:
The cloudinary config file:
import { config, uploader } from 'cloudinary'
import dotenv from 'dotenv';
dotenv.config();
const cloudinaryConfig = (req, res, next) => {
config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
next();
}
export { cloudinaryConfig, uploader };
The multer config file:
import multer from 'multer';
import Datauri from 'datauri';
import path from 'path';
const storage = multer.memoryStorage();
const multerUploads = multer({ storage }).single('image');
const dUri = new Datauri();
/**
* #description This function converts the buffer to data url
* #param {Object} req containing the field object
* #returns {String} The data url from the string buffer
*/
const dataUri = req => dUri.format(path.extname(req.file.originalname).toString(), req.file.buffer);
export { multerUploads, dataUri };
The entry point file(app.js)
import express from 'express';
import { urlencoded, json } from 'body-parser';
import { resolve } from 'path';
import { uploader, cloudinaryConfig } from './config/cloudinaryConfig'
import { multerUploads, dataUri } from './middlewares/multerUpload';
const app = express();
const Port = process.env.PORT || 3000;
app.use(express.static(resolve(__dirname, 'src/public')));
app.use(urlencoded({ extended: false }));
app.use(json());
app.use('*', cloudinaryConfig);
**app.post('/upload', multerUploads, (req, res) => {**
if(req.file) {
const file = dataUri(req).content;
return uploader.upload(file).then((result) => {
const image = result.url;
return res.status(200).json({
messge: 'Your image has been uploaded successfully to cloudinary',
data: {
image
}
})
}).catch((err) => res.status(400).json({
messge: 'something went wrong while processing your request',
data: {
err
}
}))
}
});
app.listen(Port, () => console.log(`Server started at http://localhost:${Port}`));
I have tried to split the functions and call them in the application routes but req.file was undefined while for the other scenario, the url wasn't generated and no error was thrown. I have also looked at the express documentation to see if I can store the result of a route in a variable but I didn't see anything like so written.
carRouter.post('/car', verifyToken, postAdchecker, cloudinaryConfig, multerUploads, postCarAd);
I want the result of the upload route which is the url generated to be passed into another route(postCarAd) as a field(imageurl). How do I make that happen?

Dropzonejs and Node/Multer photo uploads are not showing on the server.

Using DropzoneJs to upload files to a Node server using Multer, I am unable to save files nor see anything in the req.file or req.files object in the console.
Here is the HTML, with a sprinkle of EJS:
<div class="container">
<div class="row dropzone_input_div">
<h1 class="new_event_header">Add Your photos for <%= event.title %></h1>
<div>
<form class="dropzone needsclick dz-clickable" action="/testmedia" id="dropzoneFileUpload" name="mediaFile" enctype="multipart/form-data">
<input type="text" value="<%= event._id %>" hidden name="id">
</form>
</div>
</div>
<div class="row">
<div class="dropzone_preview">
</div>
</div>
</div>
Here is the Dropzone JS file:
Dropzone.options.dropzoneFileUpload={
paramName: "media",
parallelUploads: 30,
uploadMultiple: true,
autoProcessQueue: true
}
Here is the Node/Express/Router I am using:
const multer = require('multer');
// const upload = multer({dest:'uploads/'})
const async = require('async');
const dotenv = require('dotenv');
require('dotenv').config({silence:true});
const router = express.Router();
//Add Mongo Models to use Mongoose
const { Event, User, Moments, Instant } = require("../models");
const b2 = new B2({
accountId: process.env.B2_MASTER_APPLICATION_KEY,
applicationKey: process.env.B2_WRITE_APPLICATION_KEY
});
//router.use('/testmedia',upload.single('uploadedFile'))
router.use(multer({dest: 'uploads/'}).single('file'));
const uploads = (req,res,next) => {
console.log("hit uploads yall!");
console.log(req.file);
next();
}
const testMedia = (req,res) => {
console.log("hit testMedia route");
res.send("File uplaoded!")
}
My console.log files look like this...
hit uploads yall!
undefined
hit testMedia route
POST /testmedia 200 5.603 ms - 14
Any clue why I cannot see the files? They do not save to my /uploads file on my server (Ubuntu) and always show up undefined in the console?
My friend Eli, helped me solve this...
Steps I took:
had my browser console opened in Chrome to the network tab
uploaded a file
looked for the testmedia request
at the bottom of the window there was a Form Data section with file[0]:
(binary)
Inside my routes file I used this
const express = require('express');
const passport = require('passport');
const crypto = require('crypto');
const flash = require('express-flash');
const xoauth2 = require('xoauth2');
const B2 = require('backblaze-b2');
const async = require('async');
const multer = require('multer');
const { User } = require("../models");
const {
testMedia
} = require('../controllers/backblaze.controller')
const router = express.Router();
//*******************Middleware for Backblaze routes******************
const storeImage = multer.diskStorage({
destination: (req,file,cb) => {
cb(null, 'uploads/')
},
filename: (req,file,cb)=> {
cb(null,file.fieldname + '-'+ Date.now())
}
});
const upload = multer({storage:storeImage})
//*****THE ANSWER IS BELOW THIS LINE IN THE .single() method*****
router.post("/testmedia", upload.single('file[0]'), testMedia);
//router.post("/testmedia", upload.any(), testMedia);
The function I require is in another folder for testMedia and it looks like this
const testMedia = (req,res) => {
console.log("hit testMedia route");
res.send("File uplaoded!")
}
I'm not doing anything with the file yet, but that was my solution, the architecture is a bit different but this question is about the steps above and getting the solution through the browser and calling it correctly in the single('name') method in multer

Categories