Expo json Unexpected End of Input - javascript

I have a pretty simple bit of javascript that sends a post command. As expected, I get a promise from the fetch command, but when trying to use the promise with response.json() I get an Unexpected end of input Syntax Error at the line indicated below. I get no issue when using response.text() and various other methods, it just seems to be .json() that breaks stuff. I am using React Native and this same code has worked fine with Node.js.
async function postData (url, data) {
const params = {
mode: 'no-cors',
method: 'POST',
headers:{
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
let response = await fetch(url,params);
var responseJson = await response.json();//This seems to be the problem
return response;
}
Here is some more code that may be helpful.
function postStuff() {
var url = "http://192.4.20.69:1337";
postData(url, data)
.then(res => {
console.log(res);
});
}
export default function App() {
console.log("App Executed");
return (
<View style={styles.container}>
<StatusBar style="auto" />
<Text>Hello!!</Text>
<Button
title="Post"
color={"#696969"}
accessibilityLabel="Click to send message"
onPress={postStuff}
/>
</View>
);
}
Any help figuring out why .json() is breaking this would be appreciated. I'd like to try sticking with using fetch but if I need to I can use one of the other ways of handling json but I think I may still run into the issue concerning .json().

Probably the issue lies in the server side response.
response.json() fail if no json is returned.
I suggest to you to check server response by adding a try catch around response.json() and print out response.text() in the catch .
It could also be due to the fact that your response is missing the required header content-type and fetch doesn't know how to parse it.
So you could try yo do something like this
async function postData (url, data) {
const params = {
mode: 'no-cors',
method: 'POST',
headers:{
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
let response = await fetch(url,params);
try{
return await response.json();//This seems to be the problem
}catch(e){
console.error(e);
const textResponse = await response.text();
return JSON.parse(textResponse)
}
return response;
}
Also I notice that you are returning response instead of responseJson that also could be the problem here

Related

Refactor from fetch to await that can yield same result

So I moved over a non-reusable fetch request code snippet to my API:
let response = await fetch(visitURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + userJWT
},
body: JSON.stringify(endingVisit)
});
if (response.ok) {
let {visitId, createdAt} = await response.json();
const viewVisitDto = new ViewVisitDto(`${visitId}${createdAt}${visitorId}${doctorId}${oldPatientId}`);
return viewVisitDto;
} else {
throw new Error("deactivated!")
}
I was able to get this far:
axios.post(visitURL, {
headers,
body: JSON.stringify(visit)
}).then((response) => {
console.log(response);
}).catch((error) => {
console.log(error);
})
But does not exactly give me the visitId and createdAt from the response and I cannot use a response.ok nor a response.json(). Essentially I need to pull out that visitId and createdAt that should be coming back in the response.
I also tried just using node-fetch library, but although in VS code it seems to accept it, TypeScript is not happy with it even when I do install #types/node-fetch and even when I create a type definition file for it, my API just doesn't like it.
Guessing what you are after is
// don't know axios, but if it returns a promise await it
const dto = await axios.post(visitURL, {
headers,
body: JSON.stringify(visit)
}).then((response) => {
// parse response
return {resonse.visitId, resonse.createdAt}
}).then(({visitId, createdAt}) => {
// form dto (where are other vals)?
return new ViewVisitDto(`${visitId}${createdAt}${visitorId}${doctorId}${oldPatientId}`);
}).catch((error) => {
console.log(error);
})
However - you don't mention where doctorId and oldPatientId come from... You try providing more info, including output of the console.log's and the surrounding code

Request doesn't work with URL from Response Body

Request doesn't work with the URL i get from response body. The URL prints fine in the console but working with it just doesn't work
request.post(`https://onesignal.com/api/v1/players/csv_export?app_id=${constants.ONESIGNAL_APPID}`, {
json: {
"extra_fields": ["country"]
}, headers: constants.AUTH_HEADER
}, (error, res, body) => {
if (error) {
reject(error)
return
}
console.log(body)
var csvURL = body.csv_file_url
console.log(csvURL)
request(csvURL) // <--- Request doesn't work with the csvURL from body
.pipe(fs.createWriteStream("./ji.csv.gz", { encoding: 'binary'}))
This just doesn't work! If i put the exact same printed URL string and put inside the request URL it works somehow, but if I take it from the response body directly it doesn't work.
This is the body output:
{
csv_file_url: 'https://onesignal.s3.amazonaws.com/csv_exports/theappid.csv.gz'
}
I also tried using axios instead of request but it still doesn't work
Update: Using node-fetch doesn't work either
async function getAllCountries() {
return new Promise((resolve, reject) => {
fetch(`https://onesignal.com/api/v1/players/csv_export?app_id=${constants.ONESIGNAL_APPID}`, {
method: 'post',
body: JSON.stringify({ extra_fields: ["country"] }),
headers: { 'Authorization': 'Basic ****', 'Content-Type': 'application/json' },
})
.then(res => res.json())
.then(json => {
const csvURL = json.csv_file_url
console.log(csvURL)
fetch(csvURL)
.then(
res => {
const dest = fs.createWriteStream("./ji.csv.gz");
res.body.pipe(dest);
res.body.on("end", () => {
gunzip('ji.csv.gz', 'ji.csv', async () => {
const usersCSVJSON = await csv().fromFile("ji.csv");
const onlyCountriesArray = usersCSVJSON.map((value) => { return value.country })
const singleCountries = new Set(onlyCountriesArray)
resolve([...singleCountries])
})
});
dest.on('error', (error)=> {
console("ERRORR")
})
})
})
})
}
```
First off, you don't need any special library, like Request or Axios, to do AJAX. All you need is the (built-in) fetch method (see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch for more info).
(NOTE: On Node you will need a library, eg. https://www.npmjs.com/package/node-fetch, since it sadly has no built-in fetch. But by using such a library you can then fetch the exact same way on both your client and server ... without a client library.)
Second ...
If i put the exact same printed URL string and put inside the request URL it works somehow, but if I take it from the response body directly it doesn't work.
This suggests that there is something in the response body you're not seeing. For instance, there might be a newline character, or some other special/invisible text character, at the start of the URL. If so, that could explain your problem.
To debug, I would recommend logging them side-by-side:
console.log(csvURL, '*PRINTED URL*')
to see if you can observe any difference.
Also you could try checking the .length of both strings, or doing a csvUrl.trim() to see if that helps. Ultimately though, your results are telling you that the two strings aren't the same ... because if they were, then your results would be also.
When using the url directly the file hasn't been created yet on the server so it didn't work. I needed to delay the function so now it works

Why is my fetch response showing a promise even after reading the response stream?

I'm calling an API, which is returning a body that I need to access. Calling the API via Postman works as expected. The JavaScript code is below:
async function checkIfCheater(nameToCheck) {
let testJson = {
"GameName" : nameToCheck
}
await fetch(apiGatewayCheckCheaterLocal, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(testJson)
}).then(response=>response.json()).then(data=>{ return data; });
}
I have tried accessing the response in multiple ways. The example here follows the accepted answer here. However, despite this, the returned value is still a PromiseĀ {<pending>} object that I cannot access the body of.
How come my object is still a promise, despite following the answer on that link, and how can I fix it?
It should be corrected as follow,
async function checkIfCheater(nameToCheck) {
let testJson = {
"GameName": nameToCheck
};
const res = await fetch(apiGatewayCheckCheaterLocal, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(testJson)
});
const data = await res.json();
return data;
}
checkIfCheater('name').then(data => console.log(data));

Why fetch gives response like this?

I got this kind of response from fetch when I inspect it in the console, as shown in the picture. However, when i check from the devtool Network, it shows the correct error response. Any idea on how to deal with this?
export function loginRequest(data){
return (dispatch, getState) => {
let tmp = Object.assign({},data)
var request = new Request('https://aaa.com/json', {
method: 'POST',
mode: 'cors',
headers: new Headers({
'Content-Type': 'text/plain'
})
});
fetch(request).then((res)=>{
alert(JSON.stringify(res))
dispatch({
type: types.LOGIN,
data: res
})
}).catch(err =>{
alert(JSON.stringify(err))
alert(err.errMsg)
dispatch({
type: types.LOGIN,
data: data
})
console.log(JSON.stringify(err))
})
}
}
You need to parse the response to JSON to see the response that matches what you see in the network tab.
fetch('//offline-news-api.herokuapp.com/stories')
// First you can deal with the response, checking status code, headers, etc.
.then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
// This is the line you are missing
return response.json();
})
// Now you will see the proper JSON response that should match
// what you see in the network tab.
.then(function(stories) {
console.log(stories);
});
When using fetch, you can see the raw response, which is what your screenshot seems to be, and then you can parse it to JSON to see the body of the response as you are expecting. This allows more fine-tuned control of error handling, responses, etc.
You can also use axios where you don't have to parse your response and don't have to manually reject if there's 400 errors, it will go to catch instead.

Javascript await fetch GET request with number of params

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

Categories