Invalid input file upload api platform - reactjs

I'm trying to upload a file using api platform file upload. I'm using React-redux with redux-saga to make this request, but the server keeps throwing bad request response.
Api platform documentation says the following for making the request:
This endpoint accepts standard multipart/form-data-encoded data, but
not JSON data. You will need to format your request accordingly.
My Saga:
I tried appending my uploaded file to formData and use that as body for my request.
let data = new FormData();
data.append("file", action.payload.file)
const fileResponse = yield call(
fetch,
`${api.url}/api/media_objects`,
{
method: 'POST',
mode: 'no-cors',
body: data,
headers: { 'content-type': 'multipart/form-data' }
}
);
return console.log(fileResponse);
This is the api platform example request for posting a new media object
curl -X POST
"https://api.myroute/api/media_objects" -H
"accept: application/ld+json" -H "Content-Type: multipart/form-data"
-F "file=#1.6b.jpg;type=image/jpeg"
Api platform keeps returning a 400 error, which refers to invalid input. Any idea how the valid input should look like?
For my media object entity I followed the api platform documentation, so it looks exactly the same as in the docs

Details matter
headers: { 'content-type': 'multipart/form-data' }
It should be
headers: { 'Content-Type': 'multipart/form-data' }
There is no 'content-type', only 'Content-Type' header is defined (RFC) and widely accpeted.

I had a very similar issue recently (I can't remember the exact error), with API Platform (and the MediaObject entity), and React - redux (but no redux-saga).
I was able to fix it by removing the header part of my request :
headers: { 'content-type': 'multipart/form-data' }
So my new request looked exactly like that in my case :
const formData = new FormData();
formData.append('file', file);
return fetch(id, {
method: 'POST',
body: formData
})
...
I don't really know why, but it did the trick. Maybe it is handled automatically since we send a FormData object.
Hope it can work for you too !

Related

File Upload using spring rest and axios, no multipart boundary was found

I have some issues in file uploading using spring rest and react and axios,
my back-end code is
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity uploadFile(#RequestParam MultipartFile file) {
return ResponseEntity.ok().build();
}
and I can upload file using postman, but by using axios I got some errors.
nested exception is org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
here is my code:
let formData = new FormData();
formData.append("file", this.state.selectedFile);
axios({
method: "post",
url: url,
data: {
formData
}
})
also if I put
headers: { "Content-Type": "multipart/form-data" }
I got error too,
can anyone tell me what are my mistakes please?
It may be beacause you are creating a new object and sending the data inside the object
Try this data: formData
let formData = new FormData();
formData.append("file", this.state.selectedFile);
axios({
method: "post",
url: url,
data: { formData},
{...axios.default.headers,
...{headers: { "Content-Type": "multipart/form-data" }}
}
})
You dont need to put any headers as it will automatically , decides the parameters of headers , when you do it manually you need to explicitly decides few parameters which is quite difficult to judge , so dont give headers

Axios in React app. Posting image with form data sends request with empty body

I'm trying to send image file to my backend API. Last works fine with Postman. The problem is not with image, I'm not able to send any request with axios and form data, no meter I append image or not.
Everything works fine with fetch. It took time to understand, that fetch does not need any content type, and last generates automatically as multipart/form-data with right boundary.
As written axios should do same as fetch, but it does not generate or change its content-type. Passing header 'content-type' : 'multipart/form-data does not do the trick of course. When I do not set content type it just use application/json. I was not able to find anything like that in documentation. Everywhere its says, that axios should create content type header automatically.
My axios version is 0.18.0.
Here is code, it can't be more simple =)
axios
.post(url, payload)
#######UPDATE#######
It turned out the problem was with axios interceptor. If you don't use interceptors you won't get this problem. So when I created new instance and deleted all headers no interceptors where called that's why my code worked. But let me bring more details to help others avoid this pain. Interceptor has transformRequest function where this part of code exists
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
where setContentTypeIfUnset function is
function setContentTypeIfUnset(headers, value) {
if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
headers['Content-Type'] = value;
}
}
So if your object has undefined headers you will also pass this situation. But in my case even after deleting all headers I must pass some header to my application. And on setting it interceptor calls that transfromRequest function which adds that header to my formdata request.
I hope in future releases axios will fix this issue.
#######OLD ANSWER#######
As I guessed, somehow axios in my project set its default value for header content type and even setting it as 'content-type' : undefined did not overwrite that value.
Here is solution
let axiosInstance = axios.create();
delete axiosInstance.defaults.headers;
Then use that instance.
Spent whole day to find this solution.
const formData = new FormData();
formData.append('image', image); // your image file
formData.append('description','this is optional description');
Axios.post(`your url`, {body:formData}, {
headers: {
'content-type': 'multipart/form-data'
}
})
Can you please try this code once ?
You can try like this:
axios({
method: 'post',
url: 'myurl',
data: bodyFormData,
headers: {'Content-Type': 'multipart/form-data' }
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});

can't receive monzo access token using axios

I've been trying for the whole day to perform a post request using axios in react (I'm trying to get an access_token for a Monzo app). I've followed the instructions here and they work perfectly when trying them out with the httpie command line tool as illustrated on said instructions. However, when I try to use it from within my react app, things go awry. The post request in question using httpie is as follows:
http --form POST "https://api.monzo.com/oauth2/token" \
"grant_type=authorization_code" \
"client_id=my_client_id" \
"client_secret=my_client_secret" \
"redirect_uri=my_redirect_uri" \
"code=my_authorization_code"
and this works as expected and returns a JSON object containing my access_token.
The (problematic) axios command I've been using in my react app is:
axios.post(
"https://api.monzo.com/oauth2/token", {
grant_type: "authorization_code",
client_id: my_client_id,
client_secret: my_client_secret,
redirect_uri: my_redirect_uri,
code: my_authorization_code
})
The error message I'm getting is Failed to load resource: the server responded with a status of 400 ().
I found this very related question, which suggests I add a header specifying Content-Type: application/json so I changed my axios commands to:
axios({
method: "POST",
url: "https://api.monzo.com/oauth2/token",
data: JSON.stringify({
grant_type: "authorization_code",
client_id: my_client_id,
client_secret: my_client_secret,
redirect_uri: my_redirect_uri,
code: my_authorization_code
}),
headers: {
'Content-Type': 'application/json'
}
})
which, unfortunately, gives the exact same error.
Can anybody give me a few pointers on this? I'm very new to networking...thanks!
And as it usually happens with these things, I found the answer shortly after posting the question. Apparently, the 'Content-Type' needs to be sent as 'application/xxx-form-urlencoded' and the data to be transformed accordingly like so:
const queryString = require('query-string')
axios({
method: "POST",
url: "https://api.monzo.com/oauth2/token",
data: queryString.stringify({grant_type: ...}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})

Sending POST request weird issue

I'm quite new with ANGULAR and web development in general and I'm currently working on a web tool. Now I want this tool to send a POST request to a web service but Im encountering a weird bug. Now I have below code in my javascript:
var data_info = { test_id: 'TEST', model_id: 'TEST:TEST_ID' };
//data_info = JSON.stringify(data_info);
var request_json = {
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: data_info,
cache: false,
};
console.log(request_json);
$http(request_json).then(function successCallback(response) {
// response code here
}
Now this code currently doesn't pass the preflight request check and is always returning a 405. But if I change the line data: data_info in the request JSON into a new key let's say body: data_info it now successfully sends the request and I can confirm that the service is receiving it. I'm not sure what's the issue here and can't figure it out.
change your header to :
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
Please try

Making an axios POST request with multipart/form-data, via React Native Debugger

I am trying to upload a file from React Native to my server. However I am unable to set the 'Content-Type' header to multipart/form-data.
Here's my simple request:
axios({
uri: 'http://localhost:3000',
method: 'POST',
data: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data'
}
});
I am using the React Native Debugger to monitor Network requests.
When I see my Network request inside the Debugger, I see this:
'Content-Type': 'text/plain;charset=UTF-8'
and the Request Payload is simply [object Object]
User Agent:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) ReactNativeDebugger/0.7.13 Chrome/58.0.3029.110 Electron/1.7.9 Safari/537.36
If I am unable to do this with the React Native Debugger, can anyone suggest any steps to testing via Expo.
Using the latest version of Axios (0.17.1), you make an HTTP request with 'Content-Type': 'multipart/form-data' in the header as follows:
const formData = new FormData();
formData.append('action', 'ADD');
formData.append('param', 0);
formData.append('secondParam', 0);
formData.append('file', new Blob(['test payload'], {
type: 'text/csv',
}));
axios({
url: 'http://localhost:5000/api/hello',
method: 'POST',
data: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
});
Two things: I am using url, not uri. Also, please insert your own form data and url. Inspecting the request, which has been replied successfully, this is what I get for the request header:
After hours trying to make it work, I realized that a multipart/form-data needs a boundary that is generated dynamically depending on the amount of data that is being sent.
Here is the code that works for me:
const data = new FormData();
data.append('field_name', 'field_pictures');
data.append('files[file]', fs.createReadStream(filepath), filename);
const headers = {
'Content-Type': 'multipart/form-data',
'Authorization': 'here you can set your headers',
...data.getHeaders() // this line is the key
// you need to mix your headers with those generated by the form data
}
return axios.post(url, data, { headers });
You can do simply:
axios.defaults.headers.common['Content-Type'] = 'multipart/form-data; boundary=someArbitraryUniqueString';
It will set your headers for sure. However, I have been struggling with form data in React Native for a day and without success. After some experimental aproaches, I found out that everything works without debugger. I don't know why but with debugger, I have been sending empty body to the server.
What's more I didn't need to set headers as it is your question in this post.
According to #JMA answer,
import axios from 'axios';
export async function somefunction(data) {
const formData = new FormData(); // No imports needed
for(let key in userData) {
formData.append(key.toString(), data[key].toString())
}
return axios.post(`${ROUTE}`, formData, {
'Content-Type': 'multipart/form-data',
});
}
where: data is your payload to what you want to send. somefunction is function that send POST request to ROUTE.

Resources