Fetch file to multer returns undefined - fetch

I want to fetch a file via JS to multer but it always returns undefined. I made a postman request and works perfectly and the file saves in '/uploads'. Tried to look into my JS code but don't know whats wrong.
HTML:
<form action="/" class="form" id="form" accept-charset="utf-8" onsubmit="return(validate())">
<div class="form__div">
<label class="form__label" for="image">Send an image (optional)</label>
<input type="file" name="image" id="image">
</div>
<button class="form__submit" type="submit">Submit</button>
</form>
JS:
const validate = () => {
const formData = new FormData(document.querySelector('#form'));
fetch('/send_file', {
method: 'POST',
body: formData.get('image')
})
.then(data => console.log(data))
.catch(err => console.log(err))
return false;
}
Node:
const express = require('express');
const multer = require('multer');
const app = express();
app.use(express.static('./public'));
app.use(express.json());
const storage = multer.diskStorage({
destination: './uploads',
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage });
app.listen(3000);
app.post('/send_file', upload.single('image'), (req, res) => {
console.log(req.body.image);
res.end();
})

if you are trying to send data using multer, you must put this in your form tag
enctype="multipart/form-data"

Related

Trying to run a nodejs with React but get the following error while starting my index.js node: Cannot GET /

so I just got into React and I am still trying to figure out how to do some simple stuff, but I get an error that says : 'Cannot GET /'. I am trying to do back-end also in react so I have an index.js with the following code:
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const port = 3001;
app.use(bodyParser.json());
app.use(cors());
app.post('/', (req, res) => {
res.json({
message: "Hello World!"
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
As per my App.js goes like this:
import React, { useState } from 'react';
import './App.css';
function App() {
const [message, setMessage] = useState('');
const [response, setResponse] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
fetch('http://localhost:3001', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
})
.then(res => res.json())
.then(data => setResponse(data.message))
.catch(err => console.log(err));
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<label>
Message:
<textarea value={message} onChange={e => setMessage(e.target.value)} />
</label>
<input type="submit" value="Submit" />
</form>
<div>
{response}
</div>
</div>
);
}
export default App;
Maybe there is something wrong in my html tags? I missed a pretty obv thing? I have no clue at this point that's why I am asking for everybody's help :)
expecting a textarea in localhost:3001 and a sumbit value

How to upload an image in cloudinary using a signed upload preset with nextjs?

I am trying to upload a single image file in cloudinary with Next.js.
I tried appending the API key, timestamp, the file to be uploaded. But it results in a post error.
This is the error I get when executing the following code?
POST https://api.cloudinary.com/v1_1/<cloud-name>/image/upload/ 400 (Bad Request)
AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
What did I miss?
export default function Home() {
const [img, setImg] = useState("");
const updateImage = (e) => {
setImg(e.target.files[0]);
};
const uploadImage = async (e) => {
e.preventDefault();
const data = new FormData();
const timestamp = new Date().getTime();
data.append("file", img);
data.append("upload_preset", "cloudinary_default");
data.append("api_key", "<api-key>");
data.append("timestamp", timestamp);
try {
const response = await axios.post(
`https://api.cloudinary.com/v1_1/<cloud-name>/image/upload/`,
data
);
} catch (error) {
console.log(error);
}
};
return (
<form className="text-center my-1 border p-1">
<input type="file" onChange={updateImage} />
<button className="border rounded-md p-1" onClick={uploadImage}>Upload</button>
</form>
);
}

How do I manipulate data received from an API endpoint and submit to database

The aim of my application is to take a URL submitted by a user in a form, pull data from it, manipulate that data, and then submit the manipulated data to a Postgres database.
Current Status
So far I have developed a form on the front end of the application (irrelevant validation / styling code has been removed from this excerpt):
const Feeds = ({ visible }) => {
const handleSubmit = async (e) => {
e.preventDefault();
try {
const body = { feedTitle, websiteUrl, currency, feedUrl };
await fetch('/api/form', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
console.log('body: ', body);
} catch (error) {
console.error(error);
}
};
return (
<Form onSubmit={(e) => handleSubmit(e)} id="myForm" visible={visible}>
<HeaderContainer>
<Header>Add a new feed</Header>
<HeaderDescription>Please complete all of the required fields below and submit to add a new feed.</HeaderDescription>
</HeaderContainer>
<FormContainer>
<InputContainer>
<Label>Feed title</Label>
<Input type="text" placeholder="" value={feedTitle} onChange={(e) => handleChangeFeedTitle(e)} />
</InputContainer>
<InputContainer>
<Label>Website url</Label>
<Input type="text" placeholder="" value={websiteUrl} onChange={(e) => handleChangeWebsiteUrl(e)} />
</InputContainer>
<InputContainer>
<Label>Currency</Label>
<Select onChange={(e) => handleChangeCurrency(e)} name="currency" id="currency-select">
{currencies.map((option, index) => (
<option key={index} value={option.value}>
{option.text}
</option>
))}
</Select>
</InputContainer>
<InputContainer>
<Label>Feed url</Label>
<Input type="text" placeholder="" value={feedUrl} onChange={(e) => handleChangeFeedUrl(e)} />
</InputContainer>
</FormContainer>
{allValid ? <Button type="submit" form="myForm">Save</Button> : <DisabledButton>Save</DisabledButton>}
</Form>
)
};
export default Feeds;
On submission, this POST request hits the /api/form API endpoint:
const handler = async (req, res) => {
const body = req.body;
const response = await fetch(body.feedUrl)
.then(res => res.text())
.then(content => console.log(content))
.catch(err => console.error(err));
console.log('body: ', body);
res.status(200).json({ data: `${body}` })
};
export default handler;
Here I have simply console logged the content coming back from the API. Instead I need to manipulate it using a function and then submit the manipulated data to a database using a separate function.
The Problem
My question is, where should I implement these functions so that they trigger on the server side?
Thanks

Getting the following error: Unhandled Runtime Error SyntaxError: Unexpected end of input

I am trying to send info to the backend(node.js express server) from the frontend(next.js) with the react hook form lib.
const test = () =>{
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = async data => {
const result = await fetch('http://localhost:5000/test', {mode: 'no-cors'},{
method: 'POST',
body: JSON.stringify(data),
headers: {'content-type': 'application/json'}
}).then(res=>res.json())
console.log(data);
}
return(
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("example")} />
<input type="submit" />
</form>
</div>
);
}
export default test;
and this simple .post request on the backend:
app.get('/', (req, res)=>{
res.send('test success');
})
the error is on the following line: }).then(res=>res.json())

How to upload Image from Next JS Strapi API

How can I add an image from NextJS to Strapi Media library? I Try to upload the image from the NextJS frontend, the image will be uploaded to my Strapi Media library and my Cloudinary account but the image will not be associated/linked to that particular post
Here is my code
path: components/ImageUpload.js
import { useState } from "react";
import { API_URL } from "../config/index";
import styles from "#/styles/FormImage.module.css";
export default function ImageUpload({ sportNewsId, imageUploaded }) {
const [image, setImage] = useState(null);
const handleFilechange = (e) => {
console.log(e.target.files);
setImage(e.target.files[0]);
};
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("files", image);
formData.append("ref", "sports");
formData.append("refid", sportNewsId);
formData.append("field", "image");
const res = await fetch(`${API_URL}/upload`, {
method: "POST",
body: formData,
});
if (res.ok) {
imageUploaded();
}
};
return (
<div className={styles.form}>
<h4>Upload Sport News Image</h4>
<form onSubmit={handleSubmit}>
<div className={styles.file}>
<input type="file" onChange={handleFilechange} />
<input type="submit" value="Upload" className="btn" />
</div>
</form>
</div>
);
}
path:pages/news/edit/[id].js
import Link from "next/link";
import { useState } from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import moment from "moment";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import Layout from "#/components/Layout";
import { API_URL } from "#/config/index";
import styles from "#/styles/FormEdit.module.css";
import Modal from "#/components/Modal";
import ImageUpload from "#/components/ImageUpload";
export default function EditNews({ sportNews }) {
const [values, setValues] = useState({
name: sportNews.name,
detail: sportNews.detail,
date: sportNews.date,
time: sportNews.time,
});
const [previewImage, setPreviewImage] = useState(
sportNews.image ? sportNews.image.formats.thumbnail.url : null
);
const [showModal, setShowModal] = useState(false);
const router = useRouter();
const { name, detail, date, time } = values;
const handleSubmit = async (e) => {
e.preventDefault();
const emptyFieldCheck = Object.values(values).some(
(element) => element === ""
);
if (emptyFieldCheck) {
toast.error("Please fill all input field");
}
const response = await fetch(`${API_URL}/sports/${sportNews.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
});
if (!response.ok) {
toast.error("something went wrong!!!");
} else {
const sport = await response.json();
router.push(`/news/${sport.slug}`);
}
};
const imageUploaded = async (e) => {
const res = await fetch(`${API_URL}/sports/${sportNews.id}`);
const data = await res.json();
console.log("showing =>", data);
console.log(setPreviewImage);
setPreviewImage(data.image[0].formats.thumbnail.url);
setShowModal(false);
};
const handleInputchange = (e) => {
const { name, value } = e.target;
setValues({ ...values, [name]: value });
};
return (
<Layout title="Add New Sport News">
<Link href="/news">Go Back</Link>
<h2>Add Sport News</h2>
<ToastContainer />
<form onSubmit={handleSubmit} className={styles.form}>
<div className={styles.grid}>
<div>
<label htmlFor="name">Name</label>
<input
name="name"
id="name"
type="text"
value={name}
onChange={handleInputchange}
/>
</div>
<div>
<label htmlFor="date">Date</label>
<input
name="date"
id="date"
type="date"
value={moment(date).format("yyyy-MM-DD")}
onChange={handleInputchange}
/>
</div>
<div>
<label htmlFor="time">Time</label>
<input
name="time"
id="time"
type="text"
value={time}
onChange={handleInputchange}
/>
</div>
</div>
<div>
<label htmlFor="detail">Detail</label>
<textarea
name="detail"
id="detail"
type="text"
value={detail}
onChange={handleInputchange}
/>
</div>
<input className="btn" type="submit" value="Add News" />
</form>
{/* {console.log(previewImage)} */}
{previewImage ? (
<Image src={previewImage} height={100} width={180} />
) : (
<div>
<p>No Image Available</p>
</div>
)}
<div>
<button onClick={() => setShowModal(true)} className="btn-edit">
Update Image
</button>
</div>
<Modal show={showModal} onClose={() => setShowModal(false)}>
<ImageUpload sportNewsId={sportNews.id} imageUploaded={imageUploaded} />
</Modal>
</Layout>
);
}
export async function getServerSideProps({ params: { id } }) {
const res = await fetch(`${API_URL}/sports/${id}`);
const sportNews = await res.json();
return {
props: { sportNews },
};
}
this is the error message it is showing.
how do I resolve this error, any assistance will be appreciated
Thanks a lot
For a formData you have to add a header :
'Content-Type': 'multipart/form-data'
I have been struggling during hours to find this. I am uploading a file directly from an entry and not with the /upload route but it might work the same way. Using axios for the post method here is an example :
const form = new FormData();
const postData = {
name: 'test2',
};
form.append('files.image', file);
form.append('data', JSON.stringify(postData));
await axios
.post(getStrapiURL('/ingredients'), form, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((response) => {
// Handle success.
console.log('Well done!');
console.log('Data: ', response.data);
})
.catch((error) => {
// Handle error.
console.log('An error occurred:', error.response);
});
From my observation, the problem is on the setPreviewImage line remove the [0] array brackets from the image in order to access the Cloudinary thumbnail Url you will get from the Strapi API after each image upload.
The function below should make it work
const imageUploaded = async (e) => {
const res = await fetch(`${API_URL}/sports/${sportNews.id}`);
const data = await res.json();
console.log("showing =>", data);
console.log(setPreviewImage);
setPreviewImage(data.image.formats.thumbnail.url);
setShowModal(false);
};

Resources