Sending an axios Post request with csv in its body - reactjs

What i am trying to achieve is send a post request from my frontend to back end using axios.This post request has a csv file in its body.
Using postman : postman request
My code is this:
import React, { Component } from 'react';
import axios from 'axios'
class SessionsUpdate extends Component {
state = {
selectedFile: null
}
handleSubmit = async () => {
let formData = new FormData();
formData.append('file', this.state.selectedFile);
await axios.post(
'https://localhost:8765/...',
formData,
{ headers: { 'x-observatory-auth': localStorage.getItem("token"), 'Content-Type': 'multipart/form-data' } }
)
console.log("log") //this is not printed here
}
onFileChange = event => {
this.setState({ selectedFile: event.target.files[0] });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<h1>Choose a file to store</h1>
</div>
<div>
<fieldset>
<input type="file" accept=".csv" onChange={this.onFileChange} />
</fieldset>
</div>
<input type="submit" value="Submit" />
</form>
);
}
}
export default SessionsUpdate;
So the HTML part creates a simple GUI to select a csv file from local storage and what i want is to pass this csv file to my post request.After searching online the main way i found to do this is by using formdata but it does not work on my case and i have been stuck in this for quite a while.This requests works fine on postman though.
Any ideas about what i am missing?

Related

Django API rejects file

I'm trying to send a csv file to my Django API and response with process data, but when I send it, I get the error:
django.utils.datastructures.MultiValueDictKeyError: 'file'
this is my react code:
import { useState } from 'react';
import './App.css';
function App() {
const [file, setFile] = useState(null);
const uploadFiles = e =>{
setFile(e);
}
const insertFile = async() => {
const f = new FormData();
f.append("file", file);
await fetch(
api,
{
method: 'POST',
headers: { 'content-type': 'multipart/form-data' },
body: f,
})
.then((response) => response.json())
.then((data)=>{
console.log(data);
})
.catch(error=>{
console.log(error);
});
}
return (
<>
<input type="file" name="file" onChange={(e)=>uploadFiles(e.target.files)}/>
<button onClick={()=>insertFile()}>Insertar</button>
</>
);
}
export default App;
And this is my view.py file that will process the information, for now, I just want to get the csv info in the frontend side, so the logic of how to process data doesn't matter right now.
#api_view(['POST'])
def eda(request):
file = request.FILES['file']
data = []
with open(file, encoding='utf-8') as csvf:
csvReader = csv.DictReader(csvf)
for rows in csvReader:
data.append(rows)
response = {
'csvData': data
}
return Response(response)
Seems like your files are not added in the FormData at all. It's because you are sending a list of files not a single file.
So instead of this
<input type="file" name="file" onChange={(e)=>uploadFiles(e.target.files)}/>
Use this
<input type="file" name="file" onChange={(e)=>uploadFiles(e.target.files[0])}/>
and on Django side use this:
file = request.FILES.get('file') # won't raise exception
if file is None:
# show some error response
Instead of request.FILES.get('file') try using request.data.get('file')

React axios post request does not send the data

I am using react for my app. I am learning post request. I found one dummy api site Mocky where I can test my post request. This is my api link .For post request I used axios. I don't know how the Mocky api works. I made post request. when I console log the input values I can the value.But when I console log the response it seems like it does not get the data. I don't see any where I am making mistake.
Here is my code:
import React, { useState } from 'react';
import { API_URLS } from '../utilities';
import axios from "axios";
export default function CreateAccount() {
const [state, setState] = useState({
"email": ``,
"password": ``,
"loading": false,
"error": ``
});
const onChangeStudent = (e) => {
setState({
...state,
[e.target.id]: e.target.value
});
};
const onSubmit = async (e) => {
e.preventDefault();
console.log(state);
const url = `https://run.mocky.io/v3/15c2b7ec-9f31-4a18-ae60-a7f41e1f39b2`;
const obj = {
"email": state.email,
"password": state.password
};
console.log(obj.email); //I can see the input value
console.log(obj.password);//I can see the input value
axios
.post(url, obj)
.then((res) => {
console.log(res.data); // it does not show the data
console.log(res);
})
.catch((error) => {
setState({
...state,
"error": error
});
});
};
return (
<div>
<form onSubmit={onSubmit}>
<input
type="text"
value={state.name}
onChange={onChangeStudent}
id="email"
required
/>
<input
type="password"
value={state.password}
onChange={onChangeStudent}
id="password"
required
/>
<button
className="btn waves-effect blue lighten-1"
type="submit"
name="action"
disabled={state.loading}
>
{state.loading ? `loading...` : `save`}
</button>
</form>
</div>
);
}
Hi can't seem to find anything wrong with what you are doing.
I tested the below and it worked for me. Try to change from .then to await. Hope this solves your problem. Check in your network tab if your request is successful and if you are sending the body.
try {
const response = await axios.post('https://run.mocky.io/v3/4b95050f-2bcc-4c78-b86e-6cac09372dce', data);
console.log("Response", response);
} catch(e) {
console.error(e);
}

Change file name in React-Dropzone image upload with cloudinary

I am using react-dropzone and cloudinary for image upload.
I have already made an successfull connection between my account and my react project and I am able to upload images though my react project.
I am having trouble setting the file name in the react project.
Here is the code snipped of my react project.
I have already tried something like this:
onImageDrop(files) {
console.log(files)
var test = JSON.parse(JSON.stringify(files))
test[0]["name"] = "test"
this.handleImageUpload(test);
}
But I get an error saying that the file is readonly.
Here is the working example of what I have
onImageDrop(files) {
this.handleImageUpload(files[0]);
}
handleImageUpload(file) {
let upload = request.post(CLOUDINARY_UPLOAD_URL)
.field('upload_preset', CLOUDINARY_UPLOAD_PRESET)
.field('file', file);
upload.end((err, response) => {
if (err) {
console.error(err);
}
console.log(response)
});
}
render() {
return (
<div>
<Dropzone
onDrop={this.onImageDrop.bind(this)}cloudinary
accept="image/*"
multiple={false}>
{({ getRootProps, getInputProps }) => {
console.log("input props", getInputProps)
return (
<div
{...getRootProps()}
>
<input {...getInputProps()} />
{
<p>Try dropping some files here, or click to select files to upload.</p>
}
</div>
)
}}
</Dropzone>
</div>
)
}
How do I change the file name before I send it to cloudfire?
You can set the image name on Cloudinary when uploading by setting the public_id.
For example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Upload extends React.Component {
processFile = async e => {
var file = e.target.files[0];
var formdata = new FormData();
formdata.append("file", file);
formdata.append("cloud_name", "XXXX");
formdata.append("upload_preset", "XXXX");
formdata.append("public_id", "my-name1");
let res = await fetch(
"https://api.cloudinary.com/v1_1/<Cloud-Name>/auto/upload",
{
method: "post",
mode: "cors",
body: formdata
}
);
let json = await res.json();
console.log(JSON.stringify(json.secure_url));
};
render() {
return (
<div>
<h3>Upload</h3>
<input type="file" onChange={this.processFile} />
</div>
);
}
}
ReactDOM.render(<Upload />, document.getElementById("container"));

Axios data coming up as ImmutableMultiDict([]) when sent to Flask POST route, but work with Postman

I am using Flask to create a POST method to register a new user in my MySQL database. I tried created an Axios method to send the POST request from my React JS application. I was testing with Postman, and I am sending it using application/x-www-form-urlencoded. The registration works in Postman, but the data comes up as ImmutableMultiDict([]).
Flask code:
#app.route('/registerUser', methods=['POST'])
def registerUser():
data = request.form
if len(data) is 0:
return 'Request was empty!'
username = data['username']
password = data['password']
email = data['email']
user = User(username=username,
password=password,
email=email)
db.session.add(user)
db.session.commit()
return 'Registration success!'
return 'Registration failed!'
React code:
class Signup extends Component {
constructor(props){
super(props);
this.state = {
username: '',
password: '',
email: ''
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.clearInputs = this.clearInputs.bind(this);
}
handleChange(event){
event.preventDefault();
this.setState({[event.target.name]: event.target.value});
}
handleSubmit(event){
event.preventDefault();
const config = {
headers: { 'content-type': 'application/x-www-form-urlencoded' }
}
axios.post(`http://localhost:5000/registerUser`,
this.state, config)
.then(res => {
alert(res.data);
})
.catch((err) => {
alert(err);
});
}
render(){
return (
<div className='signup'>
<form onSubmit={this.handleSubmit}>
<label>
Username
<input type='text' name='username'
value={this.state.username}
onChange={this.handleChange}/><br/>
</label>
<label>
Password
<input type='password' name='password'
value={this.state.password}
onChange={this.handleChange}/><br/>
</label>
<label>
Email
<input type='text' name='email'
value={this.state.email}
onChange={this.handleChange}/><br/>
</label>
<input type='submit' value='Submit' /><br/>
</form>
</div>
);
}
}
export default Signup;
Why is the data not properly sending from Axios? I am using CORS in flask, and both Postman and Axios should be sending the same form data.
EDIT: I changed the POST request to use request.form
However, Postman works, but Axios still doesn't.
From Postman:
ImmutableMultiDict([('username', 'person'), ('password', 'Password1'), ('email', 'example#example.com')])
From Axios: ImmutableMultiDict([('{"username":"someone","password":"Password1","email":"email#example.com"}', '')])
Is Axios misconfigured?
I figured out the problem. By default, Axios sends data by JSON format. In order to comply with urlencoded, you would need to build a new URLSearchParams object to send instead. See the documentation
This is the working React code:
handleSubmit(event){
event.preventDefault();
const config = {
headers: { 'content-type': 'application/x-www-form-urlencoded' }
}
const getParams = (obj) => {
const params = new URLSearchParams();
const keys = Object.keys(obj);
for(let k of keys){
params.append(k, obj[k]);
}
return params;
}
axios.post(`http://localhost:5000/registerUser`,
getParams(this.state), config)
.then(res => {
alert(res.data);
this.clearInputs();
})
.catch((err) => {
alert(err);
});
}
This works with my OP Flask code.
I think you will have to coerce the request data into type JSON within your registerUser route since you're trying to access a JSON response but you sent the request over in application/x-www-form-urlencoded format. application/x-www-form-urlencoded is the default form content type specification created by the W3C and is usually used to send text/ASCII data. Maybe you could try the following and see if you get the expected JSON response:
app.route('/registerUser', methods=['POST'])
def registerUser():
requestJson = request.get_json(force=True)
# check that requestJson is correct if so
# create and save your new user to your db
return 'Registration failed!'
If your requestJson is as expected then you can just pull out the required fields and save your new user to your database. If not please print out the request you're receiving to see how it can be appropriately parsed.
Hopefully that helps!

Image uploading using reactjs, does not save image path in the database

I am using Rails API in the backend and ReactJS in frontend. I am also using carrier-wave for processing my image in the backend. I tried to upload my image and send it to the backend. The image files are being captured in the frontend by using simple HTML uploader.
This is my uploader.jsx
import React from 'react'
import axios, { post } from 'axios';
import { PORT } from '../constant.js';
class PrescriptionNew extends React.Component {
constructor(props) {
super(props);
this.state ={
file: null
}
this.onFormSubmit = this.onFormSubmit.bind(this)
this.onChange = this.onChange.bind(this)
this.fileUpload = this.fileUpload.bind(this)
}
onFormSubmit(e){
e.preventDefault() // Stop form submit
this.fileUpload(this.state.file).then(response => {
console.log('response', response.data)
})
}
onChange(e) {
this.setState({file: e.target.files[0]})
}
fileUpload(file){
const url = `${PORT}/prescriptions`;
var FormData = require('form-data');
const formData = new FormData();
formData.append('file',file)
const config = {
headers: {
'content-type': 'multipart/form-data'
}
}
return post(url,formData, config)
}
render() {
if (this.state.file !== null) {
console.log('this.file', this.state.file.name)
}
return (
<form onSubmit={this.onFormSubmit}>
<h1>File Upload</h1>
<input type="file" onChange={this.onChange} />
<button type="submit">Upload</button>
</form>
)
}
}
export default PrescriptionNew;
The above code is an exact replica of this solution.I have used formData and axios in order to PUSH the data to the backend. But the datas are stored as a "nil" values in the database.
console.log(formData) gives an empty hash.
My Controller code in backend side is
def create
#prescription = Prescription.new(prescription_params)
#prescription.user = current_user
unless #prescription.save
render json: { status: 200, errors: #prescription.errors } and return
else
render :show
end
end
I have also refered many solution given in this portal. But still , cannot able to study whats going wrong in my code.
The simple solution is to populate FormData. Returning an empty FormData will store 'nil' values in the database.
The perfect soution is
class PrescriptionNew extends Component {
upload_image(){
var element = document.getElementById("image-form")
var formData = new FormData(element);
const url = `${PORT}/prescriptions`
fetch(url,{
method: "POST",
body: formData
})
.then(response => response.json)
}
after_submit(event){
event.preventDefault();
}
render(){
return(
<div>
<h3 className="index-title">Upload Your Prescription</h3>
<form onSubmit={event => this.after_submit(event)} id="image-form" encType='multipart/form-data'>
<input type="file" name="image_path"/>
<button onClick={() => this.upload_image()}>Upload</button>
</form>
</div>
)
}
}
export default PrescriptionNew;

Resources