How control javascript error when json is empty - javascript

I am parsing a JSON file in javascript. Every 5 minutes the JSON is autoimatically updated with new data, during the time it is being updated the JSON is blank (for a about 2 seconds).
I get this error
Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at fetch.then.res
This is the code in javascript for parsing the JSON:
fetch("http://location/file/data.json")
.then(res => res.json())
.then(data => {
//do something
})
How do I control this so that it doesn't flag this error? I still want an a customer error to appear using console.log(Error()).
Any help is appreciated.

This should do the trick. then() takes a second callback function as argument that receives the error object.
fetch("http://location/file/data.json")
.then(res => res.json(), err => console.log(err))
.then(data => {
//do something
}, err => console.log(err))
EDIT: As per comment, this way is preferred. Can read more about using promises in this link
fetch("http://location/file/data.json")
.then(res => res.json())
.then(data => {
//do something
})
.catch(err => console.log(err)

You can add .catch into your processing:
fetch("http://location/file/data.json")
.then(res => res.json())
.then(data => {
// do something
})
.catch(err => console.log(err.message))
EDIT: err.message instead of JSON.stringify(err).

Related

Proper Javascript promise construction using finally()

I am building out an Express API built with the mssql package.
If I don't call sql.close() then I get the following error:
Error: Global connection already exists. Call sql.close() first.
I'd like to keep the endpoints easy to follow and maintain and like the following pattern using a finally promise pattern.
const sql = require("mssql")
const config = require("../config")
sql.connect(config.properties).then(pool => {
return pool.request()
.execute('chain')
.then(response => {
res.send(response['recordsets'][0][0]['response'])
})
.catch(err => res.send(err))
.finally(sql.close())
})
However, this generates the following error:
{
"code": "ENOTOPEN",
"name": "ConnectionError"
}
The following code works, but it seems a bit clumsy to define sql.close multiple times in the same function.
sql.connect(config.properties).then(pool => {
return pool.request()
.execute('chain')
.then(response => {
res.send(response['recordsets'][0][0]['response'])
sql.close()
})
.catch(err => {
res.send(err)
sql.close()
})
})
Is there a way to call sql.close as part of the promise chain after either a response or error is sent with res.send?
.finally accepts function, you passing result of function
sql.connect(config.properties).then(pool => {
return pool.request()
.execute('chain')
.then(response => {
res.send(response['recordsets'][0][0]['response'])
})
.catch(err => res.send(err))
.finally(() => sql.close()) // FIX HERE
})

How to Store Fetch API JSON Response in a JavaScript Object

I want to store a Fetch API JSON as a JavaScript object, so I can use it elsewhere. The console.log test works, but I can't access the data.
The Following Works: It shows console entries with three to-do items:
fetch('http://localhost:3000/api/todos')
.then(data => data.json())
.then(success => console.log(success));
The Following Does Not Work:
fetch('http://localhost:3000/api/todos')
.then(data => data.json())
.then(success => JSON.parse(success));
If I try to access success, it does not contain any data.
Have tried console.log, which works.
Have also tried the following, which works:
fetch('http://localhost:3000/api/todos')
.then(res => res.json())
.then(data => {
let output = '';
data.forEach(function (todo) {
output += `
<ul>
<li>ID: ${todo.id}</li>
<li>Title: ${todo.title}</li>
<li>IsDone: ${todo.isdone}</li>
</ul>
`;
});
document.getElementById('ToDoList').innerHTML = output;
return output;
})
.catch(err => console.log('Something went wrong: ', err));
However, I can't manually update inner HTML; I need the object to do other UX.
You can also use a function like below:
function doSomething(success){
//do whatever you like
}
fetch('http://localhost:3000/api/todos')
.then(data => data.json())
.then(success => doSomething(success));
You can just declare a variable outside and assign your result to it like this
var yourTodos;
fetch('http://localhost:3000/api/todos')
.then(data => data.json())
.then(success => yourTodos = success);
Then you have the yourTodos as your javascript object that you can use whatever you want.
You can use async await like below
async function consumingFunc () {
let response = await fetch('http://localhost:3000/api/todos')
console.log(response)
}
consumingFunc()

Why does logging the result of fetch() "break" it ("body stream is locked")?

In trying to understand a return result, I ended up with this simple thing:
fetch('http://localhost:8081/position', {mode: 'cors'})
.then(response => {return response.json()})
.then(result => console.log(result));
which works - it prints the json of the response.
But this does not work:
fetch('http://localhost:8081/position', {mode: 'cors'})
.then(response => {console.log(response.json()); return response.json();})
.then(result => console.log(result));
It thows Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream is locked
Why is that?
The promise does not really break, but the problem is that .json() (and .body(), .text()) may only be called once.
The HTTP request is modeled as a stream, and you can't really read from a stream twice.
However, you can put the result of the .json() promise in a variable, and return that instead.
fetch('http://localhost:8081/position', {mode: 'cors'})
.then(response => response.json())
.then(jsonBody => { console.log(jsonBody); return jsonBody; })
.then(result => console.log(result));

Fetch using cached data when no internet connection - Javascript - React

I have a webapp that needs to use cached data when there's no internet connection. I have it working well now using a second fetch call inside the catch block but I feel this isn't the right approach.
fetch(api)
.then(resp => resp.json())
.then(json => {
this.setState({
result: json.Results,
})
})
.catch(e => {
const options = {
cache: "force-cache"
}
fetch(api, options)
.then(resp => resp.json())
.then(json => {
console.log(`failed to fetch --- using cached data`)
this.setState({
result: json.Results,
})
})
.catch(e => {
console.error("Insufficient data")
})
})
Is there a better way to go about this?
Checking for navigator.onLine was an easy conditional to avoid any issues.
https://davidwalsh.name/detecting-online

Handling network errors with fetch

I'm using the fetch API with Redux with the thunk middleware and I think the way to handle network errors is kinda strange. This is a simple async action:
const fetchData = (id) => (dispatch) => {
dispatch(requestData())
return fetch(`/my/api/${ id }`)
.then(response => response.json())
.then(json => dispatch(receiveDataSuccess(json, id)))
.catch(err => dispatch(receiveDataFail(err, id)))
}
But if there's a network error like 404 or 500 status it gets converted to a JSON parsing error like SyntaxError: Unexpected end of JSON input. To get around it I changed my action to something like this:
const fetchData = (id) => (dispatch) => {
dispatch(requestData())
return fetch(`/my/api/${ id }`)
.then(response => {
switch (response.status) {
case 200:
return response.json()
default:
// Here I just throw an error for it
// to be catched by the promise chain
throw {
status: response.status
}
}
})
.then(json => dispatch(receiveDataSuccess(json, id)))
.catch(err => dispatch(receiveDataFail(err, id)))
}
This way I can show a more meaningful error message to the user than just a "There was an error".
Is it the proper way to handle this or am I missing something?

Categories