In Postman I can send files and they are received fine. My client [react] isn't managing to and my server always receives undefined.
Here is my handleSubmit function and form:
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("file", e.target.file.files[0]);
dispatch(upload(formData));
};
return (
// form for uploading a file
<form onSubmit={handleSubmit} encType="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>
);
And here is my axios call:
const API_URL = "/api/uploads/";
const upload = async (file) => {
const formData = new FormData();
formData.append("file", file);
const response = await axios.post(API_URL, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
withCredentials: true,
});
return response.data;
};
am I doing something wrong? I've been debugging for hours...
I have created an API using FastApi that processes the image uploaded and return the processed image.
Here is the image upload endpoint
#app.post("/predict")
async def root(file: UploadFile = File(...)):
..............................
res,im_png = cv2.imencode(".png", bg_img)
return StreamingResponse(io.BytesIO(im_png.tobytes()), media_type="image/png")
What I have done in the frontend:
class Detect extends Component {
state = {
title: '',
content: '',
image: null
};
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
};
handleImageChange = (e) => {
this.setState({
image: e.target.files[0]
})
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state);
let form_data = new FormData();
form_data.append('image', this.state.image, this.state.image.name);
let url = 'http://127.0.0.1:8000/predict';
axios.post(url, form_data, {
headers: {
'content-type': 'multipart/form-data'
}
})
.then(res => {
console.log(res.data);
})
.catch(err => console.log(err))
};
render() {
return (
<div className="App">
<form onSubmit={this.handleSubmit}>
<p>
<input type="file"
id="image"
accept="image/png, image/jpeg" onChange={this.handleImageChange} required/>
</p>
<input type="submit"/>
</form>
</div>
);
}
}
export default Detect;
When I upload the image through frontend and submit it the API shows "Unprocessable Entity", while it was working fine when I was using Swagger UI.
What I believe is the image is not being received by the FastApi as a type that it can processed
How can I resolve this issue??
You should add your image to the FormData object, using the same key defined in the endpoint for the file upload (in your case, that is, file). Thus, you should do:
form_data.append('file', this.state.image, this.state.image.name);
Using raw HTML when I post a file to a flask server using the following I can access files from the flask request global:
<form id="uploadForm" action='upload_file' role="form" method="post" enctype=multipart/form-data>
<input type="file" id="file" name="file">
<input type=submit value=Upload>
</form>
In flask:
def post(self):
if 'file' in request.files:
....
When I try to do the same with Axios the flask request global is empty:
<form id="uploadForm" enctype="multipart/form-data" v-on:change="uploadFile">
<input type="file" id="file" name="file">
</form>
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
If I use the same uploadFile function above but remove the headers json from the axios.post method I get in the form key of my flask request object a csv list of string values (file is a .csv).
How can I get a file object sent via axios?
Add the file to a formData object, and set the Content-Type header to multipart/form-data.
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Sample application using Vue. Requires a backend server running on localhost to process the request:
var app = new Vue({
el: "#app",
data: {
file: ''
},
methods: {
submitFile() {
let formData = new FormData();
formData.append('file', this.file);
console.log('>> formData >> ', formData);
// You should have a server side REST API
axios.post('http://localhost:8080/restapi/fileupload',
formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function () {
console.log('SUCCESS!!');
})
.catch(function () {
console.log('FAILURE!!');
});
},
handleFileUpload() {
this.file = this.$refs.file.files[0];
console.log('>>>> 1st element in files array >>>> ', this.file);
}
}
});
https://codepen.io/pmarimuthu/pen/MqqaOE
If you don't want to use a FormData object (e.g. your API takes specific content-type signatures and multipart/formdata isn't one of them) then you can do this instead:
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': file.type
}
})
}
Sharing my experience with React & HTML input
Define input field
<input type="file" onChange={onChange} accept ="image/*"/>
Define onChange listener
const onChange = (e) => {
let url = "https://<server-url>/api/upload";
let file = e.target.files[0];
uploadFile(url, file);
};
const uploadFile = (url, file) => {
let formData = new FormData();
formData.append("file", file);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
fnSuccess(response);
}).catch((error) => {
fnFail(error);
});
};
const fnSuccess = (response) => {
//Add success handling
};
const fnFail = (error) => {
//Add failed handling
};
This works for me, I hope helps to someone.
var frm = $('#frm');
let formData = new FormData(frm[0]);
axios.post('your-url', formData)
.then(res => {
console.log({res});
}).catch(err => {
console.error({err});
});
this is my way:
var formData = new FormData(formElement);
// formData.append("image", imgFile.files[0]);
const res = await axios.post(
"link-handle",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
How to post file using an object in memory (like a JSON object):
import axios from 'axios';
import * as FormData from 'form-data'
async function sendData(jsonData){
// const payload = JSON.stringify({ hello: 'world'});
const payload = JSON.stringify(jsonData);
const bufferObject = Buffer.from(payload, 'utf-8');
const file = new FormData();
file.append('upload_file', bufferObject, "b.json");
const response = await axios.post(
lovelyURL,
file,
headers: file.getHeaders()
).toPromise();
console.log(response?.data);
}
There is an issue with Axios version 0.25.0 > to 0.27.2 where FormData object in a PUT request is not handled correctly if you have appended more than one field but is fine with one field containing a file, POST works fine.
Also Axios 0.25.0+ automatically sets the correct headers so there is no need to specify Content-Type.
For me the error was the actual parameter name in my controller... Took me a while to figure out, perhaps it will help someone. Im using Next.js / .Net 6
Client:
export const test = async (event: any) => {
const token = useAuthStore.getState().token;
console.log(event + 'the event')
if (token) {
const formData = new FormData();
formData.append("img", event);
const res = await axios.post(baseUrl + '/products/uploadproductimage', formData, {
headers: {
'Authorization': `bearer ${token}`
}
})
return res
}
return null
}
Server:
[HttpPost("uploadproductimage")]
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
{
return Ok();
}
Error here because server is expecting param "image" and not "img:
formData.append("img", event);
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
I'm trying to send .xml file from my PC to a server, but im getting this error:
POST https://localhost:44391/api/edit net::ERR_ABORTED 415
File state
const [file, setFile] = useState();
Input and button
<input type="file" id="file" onChange={(e) => setFile(e.target.files[0])} />
<button onClick={send}>DASD</button>
Onclick function
const send = async () => {
if (file) {
let formData = new FormData();
formData.append('file', file);
console.log(formData);
await fetch("https://localhost:44391/api/edit",
{ method: "POST", body: formData });
}
}
Remove the content type from the header, as the content type is not 'text/xml it should be multipart/form-data.
Fetch api will automatically add the header based on the content. Which will be something Content-Type: multipart/form-data; boundary=—-WebKitFormBoundaryfgtsKTYLsT7PNUVD
const send = async () => {
if (file) {
let formData = new FormData();
formData.append("file", file);
console.log(formData);
await fetch("https://localhost:44391/api/edit", {
method: "POST",
body: formData
});
}
};
I have this handler to make api calls to an endpoint:
handleFileChange(e) {
e.preventDefault();
fetch(apiAddress)
.then((res) => {
return res.json()
}).then( (res) => {
this.props.onFileChange(JSON.stringify(res));
});
}
And i would like send a file as part of the requests like this:
render(){
getScene();
return (
<form>
<input type='file' name='uploaded_file' />
<button onClick={this.handleFileChange}>Upload</button>
</form>
)
}
How can it do that with the file added in that form?
This is just as simple as POSTing the File to the API:
handleFileChange(e) {
e.preventDefault();
let fileInput = document.getElementsByName("uploaded_file")[0];
fetch('/yourEndpoint', {
method: 'POST'
body: fileInput.files[0] // This is your file object
headers: {
"Content-Type": fileInput.files[0].type // this is the MIME type of the data *
},
}).then(
response => response.json()
).then( res => {
this.props.onFileChange(JSON.stringify(res))
});
}
* note, however, that this is generated from the file extension, so it can easily be spoofed