Search code examples
jsonobjectpython-requestsfetch

Javascript - Return json from fetch in an Object


I'm trying to make an application to get the recipes from https://edamam.com and I'm using fetch and Request object. I need to make 3 request, and i thought that most beautiful way for do it is make an Object and a method that return the data in JSON. I declarated into constructor a variable called this.dataJson, and i want to save there the data in JSON from the response. For that purpose i use this. The problem is that i have a undefined variable.

.then( data => {this.dataJson=data;
    console.log(data)} )

This is all my code.

class Recipe{
  constructor(url){
    this.url=url;
    this.dataJson;
    this.response;
    
  }
  getJson(){
    var obj;
    fetch(new Request(this.url,{method: 'GET'}))
    .then( response => response.json())
    .then( data => {this.dataJson=data;
    console.log(data)} )
    .catch( e => console.error( 'Something went wrong' ) );
    
  }
  getData(){
    console.log("NO UNDFEIND"+this.dataJson);
  }
  
}
const pa= new Recipe('https://api.edamam.com/search?...');
pa.getJson();
pa.getData();

I'm new studying OOP in JS and more new in Fetch requests... If you guys can help me... Thanks very much!


Solution

  • Here's a solution using async-await (and a placeholder API):

    class Recipe {
      constructor(url) {
        this.url = url;
        this.dataJson;
        this.response;
    
      }
      // the async keyword ensures that this function returns
      // a Promise object -> we can use .then() later (1)
      async getJson() {
        try {
          const response = await fetch(new Request(this.url, {
            method: 'GET'
          }))
          const json = await response.json()
          this.dataJson = json
        } catch (e) {
          console.error('Something went wrong', e)
        }
      }
      getData() {
        console.log("NO UNDFEIND:", this.dataJson);
      }
    
    }
    const pa = new Recipe('https://jsonplaceholder.typicode.com/todos/1');
    // 1 - here we can use the "then", as pa.getJson() returns
    // a Promise object
    pa.getJson()
      .then(() => {
        pa.getData()
      });

    If we want to stay closer to your code, then:

    class Recipe {
      constructor(url) {
        this.url = url;
        this.dataJson;
        this.response;
    
      }
      getJson() {
        // var obj; // not needed
        // the "fetch" always returns a Promise object
        return fetch(new Request(this.url, { // return the fetch!
            method: 'GET'
          }))
          .then(response => response.json())
          .then(data => {
            this.dataJson = data;
            // console.log(data) // not needed
          })
          .catch(e => console.error('Something went wrong'));
    
      }
      getData() {
        console.log("NO UNDFEIND:", this.dataJson); // different syntax here
      }
    
    }
    const pa = new Recipe('https://jsonplaceholder.typicode.com/todos/1');
    
    // using "then", because the "fetch" returned a Promise object
    pa.getJson()
      .then(() => {
        pa.getData();
      });

    The problem with your original code is that you initiate the request (pa.getJson()) and then immediately (on the next line) you want to read the data (pa.getData()). pa.getData() is called synchronously (so it happens in milliseconds), but the request is asynchronous - the data needs time to arrive (probably hundreds of milliseconds) - so, it's not there when you try to read it (it simply hasn't arrived yet).

    To avoid this you have to use a technique to handle this asynchronous nature of the request:

    • use a callback function (blee - so last decade)
    • use a Promise object with then() (much better) or async-await (yeee!)

    and call the pa.getData() when the response has arrived (inside the callback function, in the then() or after awaiting the result).