New to NodeJS and JavaScript
I am using NodeJS to make an API call to return some JSON data within an async function. Presently, the API call is working as intended and I have parsed the data that I am looking for. The trouble I am having is using that parsed json data as a condition within an IF statement so I can continue along with the rest of the scripts intended functions. To simplify for the mean time I have written it to display a string statement if the JSON data is what I expect it to be:
const fetch = require("node-fetch");
var accessToken = "Bearer <ACCESS TOKEN>";
var url = '<API ENDPOINT>';
var headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': accessToken
};
const getData = async url => {
try {
const response = await fetch(url, {method: "Get", headers: headers});
const json = await response.json();
console.log(json.status);
return json.status
} catch (error) {
console.log(error);
}
};
let apiStatus = getData(url);
let activated = "ACTIVATED";
let configured = "CONFIGURED";
if (apiStatus.toString() !== activated) {
console.log("BLAH");
}
Essentially, if the return value of "json.status" is equal to "ACTIVATED", then I will perform an action. Else, I will perform a different action.
At present, I am unable to use the output of the "getData()" to be used in an IF condition. Any assistance with next steps would be appreciated.
You need to wait for the promise to be resolved, because right now you'd be evaluating a Promise (pending) object.
Your getData() function is fine.
let apiStatus = await getData(url);
I don't think async works on the window scope, you can try this out. If this doesn't work, then you just need to wait for the promise to be resolved.
getData(url).then(
status => {
if (status.toString() === 'activated'){
...
}
});
I work with a Backend API which returns different data types for different requests to the same endpoint. While a more appropriate solution would be to unify the data type returned, legacy, time and lack of tests play against this solution.
I am centralizing my call method to be used by other parts of the application which need to call the endpoint. This call method implements fetch. For information:
export default function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
return fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
}).then(async (response) => {
let body: IServerResponseObjectBody = {
message: '',
code: ''
};
if (response) {
body = await response.json();
}
return {
status: response.status,
body
};
});
}
As I receive data, I am using the Response.json method to decode it.
if (response) {
body = await response.json();
}
The problem is that sometimes I receive no data (when the user is not authenticated - although that's an edge case) or the server responds with just a boolean.
In that case, the json() execution fails, because we are not handling JSON data.
ie:
FetchError: invalid json response body at http://localhost:4545/api/definition/isNameUnique/used%20name reason: Unexpected end of JSON input
I am wondering if there is a cleaner way than nesting try/catches to determine which decode method to use from the ones available: https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods
This feels like a potential solution: https://developer.mozilla.org/en-US/docs/Web/API/Body#Properties but the documentation is not too explicit and lacks examples on how to use it.
It sounds to me like you want to use text to read the response, then look at the resulting text and decide what to do. Roughly:
const text = await response.text();
if (!text) {
// no response, act accordingly
} else if (reBool.test(text)) {
// boolean response, determine whether it's true or false and act on it
} else {
// JSON response, parse it
data = JSON.parse(text);
// ...then use it
}
...where reBool is a regular expression to test for the boolean the server sometimes returns, for instance /^(?:true|false)$/i.
If the response may have whitespace, you might trim the result of response.text().
There are some unrelated things you might also want to do:
You're not checking for a successful response (this is a mistake a lot of people make, so many I wrote it up on my otherwise-anemic little blog). Check response.ok before using json or text, etc.
It doesn't make much sense to pass an async function into then as a callback. If you're going to go async, do it earlier, by making call an async function, then work with await throughout the body rather than mixing your metaphors...
Addressing those and folding in the main answer above (you'll need to adjust as necessary, either IServerResponseObject needs changing or you need to do something different with boolean responses):
const reBool = /^(?:true|false)$/i;
export default async function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
const response = await fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
});
const {status} = response;
if (!response.ok) {
throw new Error("HTTP error " + status); // Or `return {status};` or similar, but making it an error is useful
}
const text = (await response.text()).trim();
let result = {status};
if (!text) {
// blank, act accordingly, perhaps:
result.body = null;
} else if (reBool.test(text)) {
result.body = text === "true";
} else {
result.body = JSON.parse(text);
}
return result;
}
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);
});
Here is my request:
axios.get(url)
.then(res => {
console.log(res.data)
})
The output is { value: 156144277082605255 }
But should be { value: 156144277082605250 }
How to deal with Big Integers in this case?
I tried to use json-bigint
But since I am getting response.data from axios as object - it doesn't help.
My colleague answered the question:
I had to transform my response.data into string.
(you may wonder - why the useless function - just to redefine default behavior, which parses string into object with JSON.parse - in here we skip this step)
axios.get(url, { transformResponse: [data => data] });
and then parse with json-bigint
JSONBigInt.parse(res.data);
Adding to the above answers, how to integrate JSONbigint with axios request and response interceptors.
import JSONbigint from 'json-bigint'
...
// request interceptor, preventing the response the default behaviour of parsing the response with JSON.parse
axios.interceptors.request.use((request) => {
request.transformResponse = [data => data]
return request
})
// response interceptor parsing the response data with JSONbigint, and returning the response
axios.interceptors.response.use((response) => {
response.data = JSONbigint.parse(response.data)
return response
}
Integers that are within the range will remain of type number and those exceeding the range will be of type BigNumber. One could additionally parse BigNumber to string if required by simply calling toString() on the keys of type BigNumber
Run this to install json-bigint: npm install json-bigint --save
Then, use the transformResponse as an option of the axios get request
const jsonBig = require('json-bigint');
let url = 'https://your-api';
axios.get(url, { transformResponse: function(response) {
return jsonBig().parse(response.data);
}});
You can also use this in the following way:
const jsonBig = require('json-bigint');
axios({
url: 'https://your-api',
method: 'get',
transformResponse: function(response) {
return jsonBig().parse(response);
},
})
React JSX project.
I'm trying to execute await fetch GET request with number of params, fails with Uncaught SyntaxError: Unexpected identifier error.
While executing the same request with Postman, it works fine.
Some syntax issue I have. What am I doing wrong?
First of all, I'm initializing the uri to some proper value.
Secondly, I'm preparing the GET options:
var options = (payload) => {
return {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
param: JSON.stringify(payload) //payload is {domainName: "idoidoido.info"}
};
};
Then, await fetch:
const response = await fetch(uri, options(param));
And, it fails with Uncaught SyntaxError: Unexpected identifier error...
I'm assuming the second parameter of fetch takes an object, but your options is a function, which must be called with the payload, so I should think your code should be
const response = await fetch(uri, options(somePayload));
Well, first of all, I hope you're using a transpiler like BabelJS, otherwise this would would fail on like 99% of all targets at present.
Your code looks fine. Since fetch returns a Promise, await can deal with it. But you have to make sure that your await statement always is located within an async function declaration. Otherwise an error is thrown at you.
So make sure your calling line has a structure like
async function getData( uri, options ) {
const response = await fetch(uri, options);
}
Succeded to solve this. Looks like query params can't be part of fetch GET request.
Solved this by preparing the request URL beforehand with URI.js.
So, the option:
const options = () => {
return {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
credentials: 'same-origin'
};
};
Then, await fetch:
const URI = require('urijs');
const request = new URI(uri).addSearch(params).toString();
const response = await fetch(uri, options());
The addSearch(params) appending the params nicely to the url:
URI("?hello=world")
.addSearch("hello", "mars")
// -> ?hello=world&hello=mars
.addSearch({ foo: ["bar", "baz"] })
// -> ?hello=world&hello=mars&foo=bar&foo=baz