How should I return data - javascript

I'm trying to understand and implement simple app. I've got two express servers, first is only sending plain object and the second is fetching it.
Inside the second app I want to build a class - Loader, that will provide fetch and get (data) methods.
class Loader{
constructor(){
this.data = {data:"some data"}
}
async fetchData(){
const res = await axios.get("http://localhost:5000/data");
if(res) {
this.data = res.data
console.log(this.data)
return res.data
}
}
getData(){
return this.data
}
async getFetchedData(){
await this.fetchData();
console.log(this.data)
this.getData();
}
}
But actually it doesn't work the way I wanted it. I'd like to implement method that will return fetched object.
const testLoader = new Loader();
testLoader.getFetchedData();
const testVar = testLoader.getData();
console.log("test", testVar)
The output is:
test { data: 'some data' }
data from fetchData { data: 'test data after fetching' }
data from getFetchedData { data: 'test data after fetching' }
And I understand - getData is sync and the rest methods are async, so that's the order of perform. But how do I need to rewrite code to receive method that will return the fetched object?

You'll need to await for any async methods to complete (or then-chain them) wherever you use them.
const testLoader = new Loader();
await testLoader.fetchData();
const testVar = testLoader.getData();
console.log("test", testVar)

you can try some code i made
class Loader{
constructor(){
this.data = {data:"some data"}
}
async fetchData(){
const res = await axios.get("http://localhost:5000/data");
this.data = res.data
}
getData(){
return this.data
}
async getFetchedData(){
await this.fetchData();
console.log(this.data)
return this.getData();
}
}
// 1
const exec = async () => {
try {
const loader = new Loader()
await loader.fetchData()
console.log(loader.getData())
} catch(e) {
console.log("ERROR", e)
}
}
exec()
// 2
const exec = async () => {
try {
const loader = new Loader()
const data = await loader.getFetchedData()
console.log(data)
} catch(e) {
console.log("ERROR", e)
}
}
exec()
// 3
const loader = new Loader()
loader.fetchData().then(() => {
console.log(loader.getData())
}).catch((e) => {
console.log("ERROR", e)
})
// 4
const loader = new Loader()
loader.getFetchedData().then((data) => {
console.log(data)
}).catch((e) => {
console.log("ERROR", e)
})

Related

Promise { <pending> } - for last async function

I have two main functions. The first one gets the SOAP data from an API. The second one parses it to json and then formats it into the object I need to store. I have been logging and seeing the return values, and as of so far until now, it's been fine. However, I am calling exports.createReturnLabelfrom my test file and all I can see is Promise { <pending> } . I am returning a value at the last function. Does this code look weird to your? How can I clean it up?
const soapRequest = require('easy-soap-request');
const xmlParser = require('xml2json')
exports.createReturnLabel = async () => {
const xml = hidden
const url = 'https://ws.paketomat.at/service-1.0.4.php';
const sampleHeaders = {
'Content-Type': 'text/xml;charset=UTF-8',
};
const auth = async () => {
const {
response
} = await soapRequest({
url: url,
headers: sampleHeaders,
xml: xml,
timeout: 2000
});
const {
body,
statusCode
} = response;
return body
}
const fetchLabel = async () => {
const soapData = await auth();
try {
const json = xmlParser.toJson(soapData)
const labelData = JSON.parse(json)["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:getLabelResponse"]
return {
courier: 'dpd',
tracking_number: labelData["return"]["paknr"],
barCode: labelData["return"]["barcodecontent"],
printLabel: labelData["return"]["label"],
_ref: null
}
} catch (e) {
return (e)
}
}
return fetchLabel()
}
calling from my test file return console.log(file.createReturnLabel())
There's an async function call inside your code.
Should be: return await fetchLabel(), so that it awaits for completion before going on its merry way.

Undefined data after storing API response to cache

I am building a simple JS application that fetches data from an API. It's working fine but now that I'm trying to implement the cache API I'm running into some issues.
My fetchData function:
function fetchUsers(){
fetch(request)
.then((response) => {
let resClone = response.clone();
response.json();
cache.storeResponse("requestsCache", request, resClone); // cache data
})
.then((data) => {
users.push(...data.users);
this.displayResults(users);
});
}
And the cache functions I'm using:
const cache = {
canUseCache: function () {
return "caches" in window;
},
getCachedResponse: async function (cacheName, request) {
if (!this.canUseCache) {
return false;
}
const openCache = await caches.open(cacheName);
const cachedResponse = await openCache.match(request);
if (!cachedResponse || !cachedResponse.ok) {
return false;
}
let cachedData = await cachedResponse.json();
return cachedData;
},
storeResponse: async function (cacheName, request, response) {
if (!this.canUseCache) {
return false;
}
const opencache = await caches.open(cacheName);
opencache.put(request, response);
},
};
After adding the cache.storeResponse line now my data is undefined. I haven't used cache before so any help would be much appreaciated.

Getting the API by the callback function in React

I have a function, that connects to the API and returns the data:
import {API_KEY, API_URL} from "./constants";
// /**
// * Fetch all tasks
// * #param {function} successCallback - Function that saves incoming data
// */
export const getOperations = async (id, successCallback) => {
try {
const response = await fetch(`${API_URL}/tasks/${id}/operations`, {
headers: {
Authorization: API_KEY,
},
});
const data = await response.json();
if (data.error) {
throw new Error('Error!');
}
successCallback(data.data);
} catch (err) {
console.log(err);
}
};
Then, in one of my react component i call that function to get a data from the specified API:
The props is a required ID.
const [operations, setOperations] = useState([])
console.log(props)
useEffect(() => {
try {
getOperations(data => (props, setOperations(data)))
} catch(e) {
console.log(e)
}
}, [])
The problem is, that my API looks like:
`...api/tasks/function%20(data)%20%7B%20%20%20%20%20%20%20%20return%20props,%20setOperations(data);%20%20%20%`20%20%20%7D/operations`
So i receive 400 error.
Could someone explain me how to get API URL in this situation like:
/api/tasks/{id}/operations
Thanks in advance.
Rather than passing the callback to the result of the function, you could just return the data.
export const getOperations = async (id) => {
try {
const response = await fetch(`${API_URL}/tasks/${id}/operations`, {
headers: {
Authorization: API_KEY,
},
});
const data = await response.json();
if (data.error) {
throw new Error('Error!');
}
return data.data;
} catch (err) {
console.log(err);
}
};
useEffect(() => {
async function apiCall() {
try {
const data = await getOperations(props.id);
setOperations(data)
} catch(err) {
console.log(err)
}
}
apiCall();
}, [props.id])

AsyncStorage.getItem returns undefined(even with .then and .parse)

I'm attempting to store data in AsyncStorage and load them back(obviously). The .setItem function works, and the notification pops up at the bottom of the iOS simulator when I call it. However, the .getItem function doesn't work, and when I console.log it, returns undefined. I have two functions to store and fetch the data:
setData = (rawDataToStore, keyToStore) => {
data_store = JSON.stringify(rawDataToStore);
AsyncStorage.setItem(keyToStore, data_store, () => {
console.warn('Stored data!')
} )
}
getData = (keyToSearch) => {
AsyncStorage.getItem(keyToSearch).then(storage => {
parsed_data = JSON.parse(storage);
return parsed_data
}).catch(e => console.warn(e))
}
I just tested the functions in my render():
to save the data:
this.setData({value: 1}, "test_data");
to load the data:
console.log(this.getData("test_data"));
The console.log just returns undefined.
I'm completely new to Asyncstorage, but what am I doing wrong?
Your console.log returns undefined ... cause, your setData function hasn't finished its job yet ... you have to await for it first, cause it's an async operation.
class YourComponent extends React.Component {
async componentDidMount() {
await this.setData();
const data = await this.getData();
console.log('data returned', data);
}
setData = async (rawDataToStore, keyToStore) => {
data_store = JSON.stringify(rawDataToStore);
await AsyncStorage.setItem(keyToStore, data_store);
};
getData = async keyToSearch => {
let parsed_data = null;
const storage = await AsyncStorage.getItem(keyToSearch);
if (storage) {
parsed_data = JSON.parse(storage);
console.log('Data in AsyncStorage: ', parsed_data);
}
return parsed_data;
};
}

Using promises in Axios requests

I am trying to work out the best way to achieve something. When I land on a Profile page, the Profile component loads the data for that profile. This is assigned to this.profile. Within this data is a path to a file, where I want to process some data using this file. To me, the below approach seems slightly risky.
created() {
let vm = this;
let url = `/api/profile/${this.$route.params.id}`;
axios.get(url).then(response => {
this.profile = response.data;
d3.json(response.data.fileName)
.then(function (data) {
//do some stuff
}).catch(function (error) {
// handle error
});
});
}
Instead of that, I want to ensure that I first have the data from the axios call. So I am thinking I need a promise? I was thinking something more along the lines off
created() {
let vm = this;
let url = `/api/profile/${this.$route.params.id}`;
axios.get(url).then(response => {
this.profile = response.data;
}).then() {
d3.json(response.data.fileName)
.then(function (data) {
//do some stuff
}).catch(function (error) {
// handle error
});
};
}
But the above is incorrect, it is mainly to show what I am trying to achieve. I was wondering how I can maybe use deferred and promises to only execute the d3 stuff once the axios call is made.
Thanks
You can solve this by chaining promises, assuming that d3.json returns a promise:
created() {
let vm = this;
let url = `/api/profile/${this.$route.params.id}`;
axios.get(url)
.then(response => {
this.profile = response.data
return d3.json(response.data.fileName)
}).then(data => {
//do some stuff
}).catch(err => {
//log error
})
}
That's where async/await comes in handy. A you don't need to save this to a variable and B you have cleaner, more readable code.
async created() {
const url = `/api/profile/${this.$route.params.id}`;
const { data } = await axios.get(url); // Optional destructuring for less clutter
this.profile = data;
const d3Data = await d3.json(data.fileName);
//do whatever you want
}
async created() {
let vm = this;
let url = `/api/profile/${this.$route.params.id}`;
try {
const {data} = await axios.get(url)
const d3Data = await d3.json(data.fileName)
} catch(err) {
//error
}
}

Categories