400 Error despite working in Postman, possible reasons? - javascript

I am using the Deepl API, and when I run the request in Postman it is successful, however using it in my app it returns only a 400 Error, which I assume means the headers aren't set up correctly, but it is just how it is in my Postman. Can anyone point out what may be the issue here?
async translateMessage(data = {}) {
const url = "https://api.deepl.com/v2/translate?auth_key=myAuthKey";
const response = await fetch(url, {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
},
body: {
text: JSON.stringify(this.text),
target_lang: 'DE',
source_lang: 'EN'
}
});
return response.json();
},
Example HTTP Post Request from Documentation:
POST /v2/translate?auth_key=[yourAuthKey]> HTTP/1.0
Host: api.deepl.com
User-Agent: YourApp
Accept: */*
Content-Length: [length]
Content-Type: application/x-www-form-urlencoded
auth_key=[yourAuthKey]&text=Hello, world&source_lang=EN&target_lang=DE

The body property of a URL-encoded message (with the application/x-www-form-urlencoded content type) must be either a string of the query parameters, or a URLSearchParams instance.
Solution
Pass the object of key/value pairs to the URLSearchParams constructor.
You might as well add auth_key (one of the required query parameters) to that, and remove it from the URL.
Remove JSON.stringify() from the text property as that would insert unnecessary quotes into the translation.
const url = 'https://api.deepl.com/v2/translate';
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
}, 1️⃣
body: new URLSearchParams({
auth_key: myAuthKey, 2️⃣
text: this.text, 3️⃣
target_lang: 'DE',
source_lang: 'EN'
})
});

Related

Why is Axios not using the Content-Type header and converting the request method to GET when PATCHing to a specific URL?

I have inherited a codebase using Axios, and I am otherwise unfamiliar with the library. This is a Node application, and I'm attempting to send a PATCH request to a third party API. Axios is configured using the following:
const axios = require('axios').create({
baseURL: process.env.API_URL,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
auth: {
username: process.env.API_USER,
password: process.env.API_PW,
},
});
I then try to make the following PATCH request:
const data = {
fields: {
field_a: 'yes',
field_b: 'no',
},
};
try {
const res = await axios.patch(`/user/${user.id}`, data, {
headers: {
'Content-Type': 'application/json'
}
});
return res;
} catch (err){
console.error(err);
}
From what I can see I'm just redefining the Content-Type header when making the patch call, but that was just an attempt to figure this out. It doesn't work either way. What I see in the response object's config property is the following (most of it is excluded):
{
headers: {
Accept: "application/json"
User-Agent: "axios/0.19.0"
},
method: 'patch',
}
Looking at the request property of the same response object I see that the method there is listed as "GET" with the Content-Type header also not listed there. It appears as though the Content-Type header is being stripped and the method is being changed to GET.
If I change nothing but the URL destination to /userWRONGPATH/${user.id} I receive, as expected, a 404 response, but the response object's config data includes this:
{
headers: {
Accept: "application/json"
Content-Length: 105
Content-Type: "application/json"
User-Agent: "axios/0.19.0"
}
}
The response object's request method is now the expected 'PATCH'. I am unsure why the patch method would work for other paths if that is in fact what is happening here.
Hello I think that the problem could be related of send the header again in Axios you define a config and that is added to all the requests.
This is an example that I use to order the project with axios.
// Axios custom config
const axiosInstance = axios.create({
baseURL: urlBase,
// timeout: 1000,
headers: { 'Content-type': 'application/json' },
});
export const apiPatchRequest = (url, id, obj) => (
axiosInstance.patch(`${url}/${id}`, obj)
);

can't send multipart with fetch but axios works fine

Here is my code:
function uploadImage(payload) {
return fetch('/api/storage/upload/image/', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
Accept: 'application/json',
Authorization: 'Bearer <token>',
},
body: payload,
});
}
function uploadImage2(payload) {
return axios.post('/api/storage/upload/image/', payload, {
headers: {
'Content-Type': 'multipart/form-data',
Accept: 'application/json',
Authorization: 'Bearer <token>',
},
});
}
function test(file, meta_data) {
var formBody = new FormData();
formBody.set('image', file);
formBody.set('meta_data', meta_data);
uploadImage(formBody);
// doesn't work
uploadImage2(formBody);
// works
}
Can someone please explain to me how I'm supposed to send multipart requests with fetch?
The error I get with this code is: 400 bad request, file and meta_data are null.
Do not use this header: 'Content-Type': 'multipart/form-data'.
Remove the header and it should work.
Explanation:
When using fetch with the 'Content-Type': 'multipart/form-data' you also have to set the boundary (the separator between the fields that are being sent in the request).
Without the boundary, the server receiving the request won't know where a field starts and where it ends.
You could set the boundary yourself, but it's better to let the browser do that automatically by removing the 'Content-Type' header altogether.
Here's some more insight: Uploading files using 'fetch' and 'FormData'
Here is what worked for me:
function uploadImage(payload) {
return fetch('/api/storage/upload/image/', {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
},
body: payload,
});
}
By comparing the cURL requests sent by the browser I discovered that in the axios request has this:
"Content-Type": "multipart/form-data; boundary=---------------------------19679527153991285751414616421",
So I figured that when you manually specify the content type, fetch respects that and doesn't touch anything while still does it's thing the way it wants:-/ so you just shouldn't specify it, fetch will know itself since you are using formData()

javascript fetch is not posting to rest api endpoint while postman is doing

I have a rest api endpoint and I am checking it using POSTMAN which is posting correctly. But, when I am doing it using JAVASCRIPT FETCH, I am not able to post it. Below is my code for fetch:
const { inputAOI, wktForCreation } = this.state
fetch('http://192.168.1.127:8080/aoi/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ userName: 'fuseim', aoiName: inputAOI, wkt: wktForCreation }),
mode: 'no-cors'
}).then(function (response) {
if (response.ok) {
return response.json()
} else {
throw new Error('Could not reach the API: ' + response.statusText)
}
}).then(function (data) {
console.log({ data })
}).catch(function (error) {
console.log({ error })
})
Below is the image for the request headers.
It is seen in the above image that in Request Headers, the Content-Type is still text/plain but I am sending application/json as shown in above fetch code.
Check the response preview in console.
Below is correct POSTMAN request:
As hinted in the comments, the problem is with the mode:"no-cors"
Content-Type is considered a simple header, and should be allowed without cors, but only with the following values:
application/x-www-form-urlencoded
multipart/form-data
text/plain
See: https://fetch.spec.whatwg.org/#simple-header
If you are running the API on the same host/port as the script, you should use mode: "same-origin" alternatively add the host/port that the script is running on as an allowed origin on the API.
For more information about CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Instead of
headers: {
'Content-Type': 'application/json'
}
you could try:
headers: new Headers({
'Content-Type': 'application/json'
})

Send data in a http post in angular 2?

I'm trying to send data with http post following differents threads, but I can't do it.
I need to send this data, tested in postman.
Headers.
Content-Type: application/x-www-form-urlencoded
Authorization: Basic user:pass
Body.
grant_type: password
scope: profile
This is my code.
login() {
let url = URL_LOGIN;
let headers = new Headers(
{
'Content-Type': 'application/json',
'Authorization': 'Basic user:pass'
});
let body = {
'grant_type': 'password',
'scope': 'profile'
}
return this.http.post(url, body, { headers: headers })
.map((response: Response) => {
var result = response.json();
return result;
})
}
Thanks in advance!!
There are two things you need to modify:
Your headers passed into the http post method missed one step. It should contain the following:
let options = new RequestOptions({ headers: headers });
Ensure you import RequestOptions from #angular/http
Then pass options into your post method as follows:
return this.http.post(url, body, options)...
The http post method body can only be a string. Therefore, it should be as follows:
let body = 'grant_type=password' + '&scope=profile';

When using mode: no-cors for a request, browser isn’t adding request header I’ve set in my frontend code

in my React app, I have the following API POST to allow the user to edit their profile (name and image).
static updateProfile(formData, user_id) {
const request = new Request(`http://localhost:4300/api/v1/profiles/${user_id}`, {
headers: new Headers({
'Authorization': getBearerToken()
}),
mode: 'no-cors',
method: "POST",
body: formData
});
return fetch(request).then(response => {
return response.json();
}).catch(error => {
return error;
});
}
The problem with the above is the header with the Authorization token is not being sent in the POST...
How can I get the Authorization header to be send in the fetch request above?
FYI, for non-multipart forms, the authorization token is sent successfully like so:
static loadProfile(user_id) {
const request = new Request(`http://localhost:4300/api/v1/profiles/${user_id}`, {
headers: new Headers({
'Authorization': getBearerToken(),
'Accept' : 'application/json',
'Content-Type' : 'application/json',
})
});
return fetch(request).then(response => {
return response.json();
}).catch(error => {
return error;
});
}
You can’t use no-cors mode if you set any special request headers, because one of effect of using it for a request is that it tells browsers to not allow your frontend JavaScript code to set any request headers other than CORS-safelisted request-headers. See the spec requirements:
To append a name/value pair to a Headers object (headers), run these steps:
Otherwise, if guard is "request-no-cors" and name/value is not a CORS-safelisted request-header, return.
In that algorithm, return equates to “return without adding that header to the Headers object”.
Authorization isn’t a CORS-safelisted request-header, so your browser won’t allow you to set if you use no-cors mode for a request. Same for Content-Type: application/json.
If the reason you’re trying to use no-cors mode is to avoid some other problem that occurs if you don’t use, the solution is to fix the underlying cause of that other problem. Because no matter what problem you might be trying to solve, no-cors mode isn’t going to turn out to be a solution in the end. It’s just going to create different problems like what you’re hitting now.
By using below code you can make a fetch request with Authorization or bearer
var url = "https://yourUrl";
var bearer = 'Bearer '+ bearer_token;
fetch(url, {
method: 'GET',
withCredentials: true,
credentials: 'include',
headers: {
'Authorization': bearer,
'X-FP-API-KEY': 'iphone',
'Content-Type': 'application/json'}
}).then((responseJson) => {
var items = JSON.parse(responseJson._bodyInit);
})
.catch(error => this.setState({
isLoading: false,
message: 'Something bad happened ' + error
}));

Categories