What the difference between these two API calls? [duplicate] - javascript

I want to set _boundry in my header.
First, I dispatch the form data:
//component.js
const form = new FormData();
form.append('email', 'eray#serviceUser.com')
form.append('password', '12121212')
dispatch(FetchLogin.action(form))
Second, I prepare api call;
//loginService.js
import api from '#/Services'
export default async form => {
const response = await api.post('user/login/', form)
return response.data
}
Third, I make api call;
//Services/index.js
import axios from 'axios'
import { Config } from '#/Config'
const instance = axios.create({
baseURL: Config.API_URL,
headers: {
'Content-Type': `multipart/form-data; boundary=${form._boundary}`, //Cannot access form here
},
timeout: 3000,
})
instance.interceptors.response.use(
response => response,
({ message, response: { data, status } }) => {
return handleError({ message, data, status })
},
)
export default instance
I want to access form data within to axios instance to be able to use form._boundry in headers.
How can I pass form data from loginService.js to Services/index.js?

This question seems to come up often enough yet I cannot seem to find a canonical answer so here goes...
When performing AJAX requests from a browser (via fetch or XMLHttpRequest), the runtime knows what to do for certain request body formats and will automatically set the appropriate Content-type header
If the request body is a FormData instance, the Content-type will be set to multipart/form-data and will also include the appropriate mime boundary tokens from the data instance.
All of these examples will post the data as multipart/form-data with appropriate mime boundary tokens
const body = new FormData();
// attach files and other fields
body.append("file", fileInput.files[0]);
body.append("foo", "foo");
body.append("bar", "bar");
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
If the request body is a URLSearchParams instance, the Content-type will be set to application/x-www-form-urlencoded
All of these examples will post the data as application/x-www-form-urlencoded
const body = new URLSearchParams({ foo: "foo", bar: "bar" });
// serialises to "foo=foo&bar=bar"
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
You only need to manually set the content-type if you intend to send string data in a particular format, eg text/xml, application/json, etc since the runtime cannot infer the type from the data.
const body = JSON.stringify({ foo: "foo", bar: "bar" });
// fetch
fetch(url, {
method: "POST",
headers: {
"content-type": "application/json",
},
body
});
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(body);
On Axios
Axios will automatically stringify JavaScript data structures passed into the data parameter and set the Content-type header to application/json so you only need minimal configuration when dealing with JSON APIs
// no extra headers, no JSON.stringify()
axios.post(url, { foo: "foo", bar: "bar" })
Under the hood, Axios uses XMLHttpRequest so the specifications for FormData and URLSearchParams also apply.
Axios v0.27.1 is broken
This specific version of Axios is unable to make a proper request with FormData. Do not use it!
Axios v1.0.0+ is broken
This is verging into my own opinion but every Axios release post v1.0.0 has been fundamentally broken in one way or another. I simply cannot recommend anyone use it for any reason.
Much better alternatives are:
The Fetch API (also available in Node v18+)
got for Node.js
ky for browsers
NodeJS
When using Axios from the backend, it will not infer Content-type headers from FormData instances. You can work around this using a request interceptor.
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
}, null, { synchronous: true });
or simply merge in the headers when making a request
axios.post(url, body, {
headers: {
"X-Any-Other-Headers": "value",
...body.getHeaders(),
},
});
See https://github.com/axios/axios#form-data
On jQuery $.ajax()
jQuery's $.ajax() method (and convenience methods like $.post()) default to sending request body payloads as application/x-www-form-urlencoded. JavaScript data structures will be automatically serialised using jQuery.param() unless told not to. If you want the browser to automatically set the Content-type header based on the body format, you also need to configure that in the options
const body = new FormData()
body.append("foo", "foo")
body.append("bar", "bar")
$.ajax({
url,
method: "POST",
data: body,
contentType: false, // let the browser figure it out
processData: false // don't attempt to serialise data
})

Related

How to take an mp3 file as input from user in React or JavaScript [duplicate]

I want to set _boundry in my header.
First, I dispatch the form data:
//component.js
const form = new FormData();
form.append('email', 'eray#serviceUser.com')
form.append('password', '12121212')
dispatch(FetchLogin.action(form))
Second, I prepare api call;
//loginService.js
import api from '#/Services'
export default async form => {
const response = await api.post('user/login/', form)
return response.data
}
Third, I make api call;
//Services/index.js
import axios from 'axios'
import { Config } from '#/Config'
const instance = axios.create({
baseURL: Config.API_URL,
headers: {
'Content-Type': `multipart/form-data; boundary=${form._boundary}`, //Cannot access form here
},
timeout: 3000,
})
instance.interceptors.response.use(
response => response,
({ message, response: { data, status } }) => {
return handleError({ message, data, status })
},
)
export default instance
I want to access form data within to axios instance to be able to use form._boundry in headers.
How can I pass form data from loginService.js to Services/index.js?
This question seems to come up often enough yet I cannot seem to find a canonical answer so here goes...
When performing AJAX requests from a browser (via fetch or XMLHttpRequest), the runtime knows what to do for certain request body formats and will automatically set the appropriate Content-type header
If the request body is a FormData instance, the Content-type will be set to multipart/form-data and will also include the appropriate mime boundary tokens from the data instance.
All of these examples will post the data as multipart/form-data with appropriate mime boundary tokens
const body = new FormData();
// attach files and other fields
body.append("file", fileInput.files[0]);
body.append("foo", "foo");
body.append("bar", "bar");
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
If the request body is a URLSearchParams instance, the Content-type will be set to application/x-www-form-urlencoded
All of these examples will post the data as application/x-www-form-urlencoded
const body = new URLSearchParams({ foo: "foo", bar: "bar" });
// serialises to "foo=foo&bar=bar"
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
You only need to manually set the content-type if you intend to send string data in a particular format, eg text/xml, application/json, etc since the runtime cannot infer the type from the data.
const body = JSON.stringify({ foo: "foo", bar: "bar" });
// fetch
fetch(url, {
method: "POST",
headers: {
"content-type": "application/json",
},
body
});
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(body);
On Axios
Axios will automatically stringify JavaScript data structures passed into the data parameter and set the Content-type header to application/json so you only need minimal configuration when dealing with JSON APIs
// no extra headers, no JSON.stringify()
axios.post(url, { foo: "foo", bar: "bar" })
Under the hood, Axios uses XMLHttpRequest so the specifications for FormData and URLSearchParams also apply.
Axios v0.27.1 is broken
This specific version of Axios is unable to make a proper request with FormData. Do not use it!
Axios v1.0.0+ is broken
This is verging into my own opinion but every Axios release post v1.0.0 has been fundamentally broken in one way or another. I simply cannot recommend anyone use it for any reason.
Much better alternatives are:
The Fetch API (also available in Node v18+)
got for Node.js
ky for browsers
NodeJS
When using Axios from the backend, it will not infer Content-type headers from FormData instances. You can work around this using a request interceptor.
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
}, null, { synchronous: true });
or simply merge in the headers when making a request
axios.post(url, body, {
headers: {
"X-Any-Other-Headers": "value",
...body.getHeaders(),
},
});
See https://github.com/axios/axios#form-data
On jQuery $.ajax()
jQuery's $.ajax() method (and convenience methods like $.post()) default to sending request body payloads as application/x-www-form-urlencoded. JavaScript data structures will be automatically serialised using jQuery.param() unless told not to. If you want the browser to automatically set the Content-type header based on the body format, you also need to configure that in the options
const body = new FormData()
body.append("foo", "foo")
body.append("bar", "bar")
$.ajax({
url,
method: "POST",
data: body,
contentType: false, // let the browser figure it out
processData: false // don't attempt to serialise data
})

Headers object for fetchAPI is always empty

I have this request function that is wrappers around the fetch API to issue request to my API. But when my frontend app issues request, the headers object is always empty. What am I doing wrong ?
export function request(method, url, payload) {
const body = JSON.stringify(payload);
const headers = new Headers();
headers.append('Content-Type', 'application/json');
const parameters = {
headers: headers,
method: method,
body: body,
cache: "default"
};
return Observable.create(observer => {
fetch(url, parameters)
.then(response => {
observer.next(response);
observer.complete();
})
.catch(error => {
observer.error(error);
});
});
}
Have you checked in the network tab of the DevTools if the headers are really missing?
I have the same trouble than you describe, my Header object seems always empty from the Chrome DevTools, but if try to check a specific header like
let headers = new Headers({'X-whatever-name': 'whatever-value'});
myHeader.has('X-whatever-name'); // returns true
Also if I check the detail of the Request Headers in the DevTools (Networking tab), I can see that my custom headers are sent properly.
So only the JS api (entries, keys, ...) seems to be broken for me, but the request is correctly sent.
Try just making it a simple object:
const headers = {
"Content-Type": "application/json"
};

When sending ajax POST FormData object key and value are not as set

I am programatically setting a FormData like so:
const formData = new FormData();
formData.append('id', '12345678');
After which I am sending a POST request with this object. (using angular HttpClient).
I am using Postman to debug the request and see what values were sent by importing the request as cURL and I see that the formData values appear differently.
key:------WebKitFormBoundaryI1mdsdmKkradYVMS\r\nContent-Disposition: form-data; name
value: "id"\r\n\r\n12345678\r\n------WebKitFormBoundaryI1mdsdmKkradYVMS--\r\n
What am I doing wrong?
I want to the send the data so that the server will receive an x-form-urlencoded request with the following object:
key: id
value: 12345678
EDIT: The solution is this:
const body = new URLSearchParams({id: "12345678"});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
})
};
return this.http.post(url, body.toString(), httpOptions).pipe(mergeMap( (response:any) => {
console.log('response ', response);
return of (response);
}));
Thanks,
Yaron
FormData objects generate multipart/form-data, not application/x-www-form-urlencoded by default.
They are designed for handling file uploads for which there are no standard encoding method in application/x-www-form-urlencoded.
Use a URLSearchParams object if you want to generate application/x-www-form-urlencoded data.
const formData = new FormData();
formData.append('id', '12345678');
const query = new URLSearchParams(formData);
console.log(query.toString());
#Quentin's answer is all good, but not that suited to Angular.
Simply pass a second parameter to your GET call :
return this.http.get<any>('url', { params: { id: '123456789' }});
You don't need to make post requests to add url parameters, and you don't need post requests if you don't provide a body.

Axios - DELETE Request With Request Body and Headers?

I'm using Axios while programming in ReactJS and I pretend to send a DELETE request to my server.
To do so I need the headers:
headers: {
'Authorization': ...
}
and the body is composed of
var payload = {
"username": ..
}
I've been searching in the inter webs and only found that the DELETE method requires a "param" and accepts no "data".
I've been trying to send it like so:
axios.delete(URL, payload, header);
or even
axios.delete(URL, {params: payload}, header);
But nothing seems to work...
Can someone tell me if it's possible (I presume it is) to send a DELETE request with both headers and body and how to do so?
So after a number of tries, I found it working.
Please follow the order sequence it's very important else it won't work
axios.delete(URL, {
headers: {
Authorization: authorizationToken
},
data: {
source: source
}
});
axios.delete does supports both request body and headers.
It accepts two parameters: url and optional config. You can use config.data to set the request body and headers as follows:
axios.delete(url, { data: { foo: "bar" }, headers: { "Authorization": "***" } });
See here - https://github.com/axios/axios/issues/897
Here is a brief summary of the formats required to send various http verbs with axios:
GET: Two ways
First method
axios.get('/user?ID=12345')
.then(function (response) {
// Do something
})
Second method
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
// Do something
})
The two above are equivalent. Observe the params keyword in the second method.
POST and PATCH
axios.post('any-url', payload).then(
// payload is the body of the request
// Do something
)
axios.patch('any-url', payload).then(
// payload is the body of the request
// Do something
)
DELETE
axios.delete('url', { data: payload }).then(
// Observe the data keyword this time. Very important
// payload is the request body
// Do something
)
Key take aways
get requests optionally need a params key to properly set query parameters
delete requests with a body need it to be set under a data key
axios.delete is passed a url and an optional configuration.
axios.delete(url[, config])
The fields available to the configuration can include the headers.
This makes it so that the API call can be written as:
const headers = {
'Authorization': 'Bearer paperboy'
}
const data = {
foo: 'bar'
}
axios.delete('https://foo.svc/resource', {headers, data})
For those who tried everything above and still don't see the payload with the request - make sure you have:
"axios": "^0.21.1" (not 0.20.0)
Then, the above solutions work
axios.delete("URL", {
headers: {
Authorization: `Bearer ${token}`,
},
data: {
var1: "var1",
var2: "var2"
},
})
You can access the payload with
req.body.var1, req.body.var2
Here's the issue:
https://github.com/axios/axios/issues/3335
For Delete, you will need to do as per the following
axios.delete("/<your endpoint>", { data:<"payload object">})
It worked for me.
I had the same issue I solved it like that:
axios.delete(url, {data:{username:"user", password:"pass"}, headers:{Authorization: "token"}})
Actually, axios.delete supports a request body.
It accepts two parameters: a URL and an optional config. That is...
axios.delete(url: string, config?: AxiosRequestConfig | undefined)
You can do the following to set the response body for the delete request:
let config = {
headers: {
Authorization: authToken
},
data: { //! Take note of the `data` keyword. This is the request body.
key: value,
... //! more `key: value` pairs as desired.
}
}
axios.delete(url, config)
I hope this helps someone!
If we have:
myData = { field1: val1, field2: val2 }
We could transform the data (JSON) into a string then send it, as a parameter, toward the backend:
axios.delete("http://localhost:[YOUR PORT]/api/delete/" + JSON.stringify(myData),
{ headers: { 'authorization': localStorage.getItem('token') } }
)
In the server side, we get our object back:
app.delete("/api/delete/:dataFromFrontEnd", requireAuth, (req, res) => {
// we could get our object back:
const myData = JSON.parse(req.params.dataFromFrontEnd)
})
Note: the answer from "x4wiz" on Feb 14 at 15:49 is more accurate to the question than mine! My solution is without the "body" (it could be helpful in some situation...)
Update: my solution is NOT working when the object has the weight of 540 Bytes (15*UUIDv4) and more (please, check the documentation for the exact value). The solution of "x4wiz" (and many others above) is way better. So, why not delete my answer? Because, it works, but mostly, it brings me most of my Stackoverflow's reputation ;-)
i found a way that's works:
axios
.delete(URL, {
params: { id: 'IDDataBase'},
headers: {
token: 'TOKEN',
},
})
.then(function (response) {
})
.catch(function (error) {
console.log(error);
});
I hope this work for you too.
To send an HTTP DELETE with some headers via axios I've done this:
const deleteUrl = "http//foo.bar.baz";
const httpReqHeaders = {
'Authorization': token,
'Content-Type': 'application/json'
};
// check the structure here: https://github.com/axios/axios#request-config
const axiosConfigObject = {headers: httpReqHeaders};
axios.delete(deleteUrl, axiosConfigObject);
The axios syntax for different HTTP verbs (GET, POST, PUT, DELETE) is tricky because sometimes the 2nd parameter is supposed to be the HTTP body, some other times (when it might not be needed) you just pass the headers as the 2nd parameter.
However let's say you need to send an HTTP POST request without an HTTP body, then you need to pass undefined as the 2nd parameter.
Bare in mind that according to the definition of the configuration object (https://github.com/axios/axios#request-config) you can still pass an HTTP body in the HTTP call via the data field when calling axios.delete, however for the HTTP DELETE verb it will be ignored.
This confusion between the 2nd parameter being sometimes the HTTP body and some other time the whole config object for axios is due to how the HTTP rules have been implemented. Sometimes an HTTP body is not needed for an HTTP call to be considered valid.
For Axios DELETE Request, you need to include request payload and headers like this under one JSON object:
axios.delete(URL, {
headers: {
'Authorization': ...
},
data: {
"username": ...
}
})
Why can't I do it easily as I do similar to POST requests?
Looking at the Axios documentation, we see that the methods for .get, .post... have a different signature:
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
Notice how only post, patch and put have the data parameter. This is because these methods are the ones that usually include a body.
Looking at RFC7231, we see that a DELETE request is not expected to have a body; if you include a body, what it will mean is not defined in the spec, and servers are not expected to understand it.
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
(From the 5th paragraph here).
In this case, if you are also in control of the server, you could decide to accept this body in the request and give it whatever semantics you want. May be you are working with somebody else's server, and they expect this body.
Because DELETE requests with bodies are not defined in the specs, and because they're not common, Axios didn't include them in those method aliases. But, because they're possible, you can do it, just takes a bit more effort.
I'd argue that it would be more conventional to include the information on the url, so you'd do:
axios.delete(
`https://example.com/user/${encodeURIComponent(username}`,
{ headers: ... }
)
or, if you want to be able to delete the user using different criteria (sometimes by username, or by email, or by id...)
axios.delete(
`https://example.com/user?username=${encodeURIComponent(username)}`,
{ headers: ... }
)
Not realated to axios but might help people tackle the problem they are looking for. PHP doesn't parse post data when preforming a delete call. Axios delete can send body content with a request.
example:
//post example
let url = 'http://local.test/test/test.php';
let formData = new FormData();
formData.append('asdf', 'asdf');
formData.append('test', 'test');
axios({
url: url,
method: 'post',
data: formData,
}).then(function (response) {
console.log(response);
})
result: $_POST Array
(
[asdf] => asdf
[test] => test
)
// delete example
axios({
url: url,
method: 'delete',
data: formData,
}).then(function (response) {
console.log(response);
})
result: $_POST Array
(
)
to get post data on delete call in php use:
file_get_contents('php://input');
axios.post('/myentity/839', {
_method: 'DELETE'
})
.then( response => {
//handle success
})
.catch( error => {
//handle failure
});
Thanks to:
https://www.mikehealy.com.au/deleting-with-axios-and-laravel/
I encountered the same problem...
I solved it by creating a custom axios instance. and using that to make a authenticated delete request..
const token = localStorage.getItem('token');
const request = axios.create({
headers: {
Authorization: token
}
});
await request.delete('<your route>, { data: { <your data> }});
I tried all of the above which did not work for me. I ended up just going with PUT (inspiration found here) and just changed my server side logic to perform a delete on this url call. (django rest framework function override).
e.g.
.put(`http://127.0.0.1:8006/api/updatetoken/20`, bayst)
.then((response) => response.data)
.catch((error) => { throw error.response.data; });
Use {data: {key: value}} JSON object, the example code snippet is given below:
// Frontend Code
axios.delete(`URL`, {
data: {id: "abcd", info: "abcd"},
})
.then(res => {
console.log(res);
});
// Backend Code (express.js)
app.delete("URL", (req, res) => {
const id = req.body.id;
const info = req.body.info;
db.query("DELETE FROM abc_table WHERE id=? AND info=?;", [id, info],
(err, result) => {
if (err) console.log(err);
else res.send(result);
}
);
});
Axios DELETE request does supports similar what POST request does, but comes in different formats.
DELETE request payload sample code:
axios.delete(url, { data: { hello: "world" }, headers: { "Authorization": "Bearer_token_here" } });
POST request payload sample code:
axios.post(url, { hello: "world" }, { headers: { "Authorization": "Bearer_token_here" } });
Noticed that { hello: "world" } is configured in different ways, but both performs same functions.
this code is generated from post man and it's perfectly work for delete api request with body.
var data = JSON.stringify({"profile":"false","cover":"true"});
var config = {
method: 'delete',
url: 'https://api.fox.com/dev/user/image',
headers: {
'Authorization': 'Bearer token',
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});

Modify the URL of a new Request Object in ES6

I'm just playing around the with Fetch API and I came across something that I can't seem to find the answer to. If I create a new request object like so:
let request = new Request('http://www.foo.com', {
method: 'GET',
mode: 'no-cors',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
});
If I then try and modify the URL (append a query string to it) I receive an error in the browser (Cannot assign to read only property). I know that usually with an object, you can set writable to 'True' but does this work the same for a request object?
The reason that I ask is that I am trying to append a querystring to the end of the URL. These options are in another object, which I've got the values of and concatenated into a string so that it's something like:
number=1&id=130&foo=bar etc.
Am I trying to over engineer what I am doing here?
You can copy all the properties from the old request into a new one with a new url like so:
const init = {
method: 'GET',
mode: 'no-cors',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
const oldRequest = new Request("https://old-url.com", init);
const newRequest = new Request("https://new-url.com", oldRequest);
console.log(newRequest.mode === oldRequest.mode); // true
console.log(newRequest.headers.get('Content-Type') === oldRequest.headers.get('Content-Type')); // true
console.log(newRequest.method === oldRequest.method); // true
Request object is immutable by design, don't try to change it.
I wish clone() instance method accepted options to be able to to tweak the cloned object, but it doesn't. So I came up with this function:
function appendQuery(urlOrReq, queryString) {
// make sure we deal with a Request object even if we got a URL string
const req = urlOrReq instanceof Request ? urlOrReq : new Request(urlOrReq);
const {
cache, credentials, headers, integrity, method,
mode, redirect, referrer, referrerPolicy, url, body
} = req;
// Don't add query string if there's none
const urlWithQuery = url + (!queryString ? '' : '?' + queryString);
return new Request(urlWithQuery, {
cache, credentials, headers, integrity, method,
mode, redirect, referrer, referrerPolicy, body
})
}
Here's the same in TypeScript (only the first line is different):
function appendQuery(urlOrReq: RequestInfo, queryString?: string): Request {
// make sure we deal with a Request object even if we got a URL string
const req = urlOrReq instanceof Request ? urlOrReq : new Request(urlOrReq);
const {
cache, credentials, headers, integrity, method,
mode, redirect, referrer, referrerPolicy, url, body
} = req;
// Don't add query string if there's none
const urlWithQuery = url + (!queryString ? '' : '?' + queryString);
return new Request(urlWithQuery, {
cache, credentials, headers, integrity, method,
mode, redirect, referrer, referrerPolicy, body
})
}
Here's how it works:
const req = new Request('https://google.com')
appendQuery(req, 'foo=42')
// => Request {method: "GET", url: "https://google.com?foo=42", headers: Headers, destination: "", referrer: "about:client", …}

Categories