Fetch json object and store in variable failed

I know the problem must have to do with async but I can’t wrap my head around how to make this work. Trying to load a json object from a file on a server and store its properties in a variable to use throughout the application.
I get Uncaught ReferenceError: someUrl is not defined
Thanks for help!

// _somejson.json

{
	"someUrl" : "/path/to/the/page",
	"someToken" : "UZVKUGV345676JHV468MHGC4678HG4C5678",
	"someEmail" : "hi@example.com",
	"someNumber" : "9283475629"
}


// javascript

var url = "./_somejson.json";
fetch(url)
    .then(res => { 
        if (!res.ok) {
            throw new Error('something went wrong');
        } 
        return res.json()
    })
    .then(data => {3
        return data.someUrl;
        someToken = data.someToken;
        someEmail = data.someEmail;
        someNumber = data.someNumber;
    })
    .catch(error => {
        console.log(error)
    })

console.log(someUrl); // Uncaught ReferenceError: someUrl is not defined

Right. I can see a few issues here.

First of all, understand that that last line will be run before the stuff inside the Promise, because the latter is async. You either need to put that stuff into the Promise or find some way to have it run after.

Next, this here, where is someUrl defined. I don’t see a variable with that name anywhere in your code.

Lastly, this:

    .then(data => {3
        return data.someUrl;
        someToken = data.someToken;
        someEmail = data.someEmail;
        someNumber = data.someNumber;
    })

You have the return on the first line? Nothing after that will get run.

I’m ignoring that “3” that is there for some unknown reason.

What do you get if you do this?

    .then(data => {
        console.log('data from inside the fetch', data);
        someToken = data.someToken;
        someEmail = data.someEmail;
        someNumber = data.someNumber;
        return data.someUrl;
    })

yes the 3 was a typo

someUrl is a property of the json object. If I define someUrl = data.someUrl in the .then code block, return it and console.log it outside the function, it’s still unknown.
I returned it before all the other properties, just to test. I know return exits the function.

How do I make the promise then? or how do I add a callback function to the fetch function? Do I put the fetch in another function with a callback? Something like…

async function fetchStuff() {
  const response = await fetch(url);
  if (!response.ok) {
    const message = `An error has occured: ${response.status}`;
    throw new Error(message);
  }
  const data = await response.json();
  return data;
}

fetchStuff().catch(error => {
  error.message; // 'An error has occurred: 404'
});

fetchStuff().then(data => {
    // console.log(data);
    var someUrl = data.someUrl;
    return someUrl;
});

But that’s just the same again, at some point I will need to use the variable someUrl outside any

someUrl is a property of the json object

OK, but that’s not the same thing as being a variable.

If I define someUrl = data.someUrl in the .then code block, return it and console.log it outside the function, it’s still unknown.

Yes, if you define it inside the then, then it is out of scope outside the function. Even if you define it outside or return it, you still have an async issue.

at some point I will need to use the variable someUrl outside any

Why? One option is to set up what you need inside the Promise. You can make that much prettier using async/await. That will take async code and make it look sync. The other option is to not try to do anything with that data until your fetch gets back, firing off whatever you need based on that event.

that sounds so logical in theory but it’s quite complicated to get right in practice.
Still don’t know how to make the promise or callback.

and data.someUrl is the property of the response, if I store that in a someUrl variable, then it’s a variable, isn’t it?

Very true.

and data.someUrl is the property of the response, if I store that in a someUrl variable, then it’s a variable, isn’t it?

Yes, but you didn’t.

But the big picture here is that you can either put what you need to do inside the then block. Or you can await and store the return value from the Promise and deal with it that way (which is really just a disguised Promise).

But yes, this is a confusing topic in JS. Different languages handle it differently. This is one of the challenges of JS. Personally, I really like using async/await, but I don’t think you can really understand those until you understand Promises.

What context is this in? As in, is it for the browser? And are you trying to load a file local to the files in the application, for example:

myApp/
  ┗ index.html
  ┗ somejson.json
  ┗ somejs.js
  ┗ somemorejs.js

I’m trying to load a file on the local server, in the file system.

OK so here’s the reason behind all of this…
I have a couple of installations of the same project, one on my local machine, one on the subdomain of the remote server and one productive installation accessible to the public.
So before I do any changes, I do them locally, then push them to the subdomain to show the client and test some more with the actual server settings, especially third party scripts, and then push to the productive installation.

However, some urls differ a bit and because they are set in the frontend, I need to hard-code them in the javascript. So everytime I change some things, I have to account for these urls and change them in each installation. So I figured I would have some peace of mind if I had a list of these variable values, all in the same place in a json file and load them dynamically in each installation. Every time I would push changes around I would just need to skip that one particular json file and done.

I now have a work-around for this because trying to make this work almost defeats the purpose of trying to make things easier.

So how do I do it now?
In almost all the cases I refer to here, I have an anchor-tag of which I leave the href empty in order to avoid it to link to a certain page and instead add an eventlistener that then later would redirect the session.
So now I figured I can just add the link to the href, server-side via php, access the href’s value and redirect in the triggered function. Need to preventdefault I guess, not sure how but it works without it too.

But I’m still curious on how to fetch, promise etc.

Yes, I do that with some of my stuff. I just throw a JSON file onto AWS S3 and just change it as needed.

It’s hard to tell what to do without knowing more about what you’re using. I am a React guy so I tend to think that way. In any case, I’m not understanding why you can’t await the fetch.

Could you put this in a minimum reproducible project and put it in a repo so we can get an idea what is going on?

I don’t understand why this won’t work:

const fetchData = async url => {
  try {
    const jsonData = await fetch(url)
    const data = await jsonData.json()
    return data
  } catch (err) {
    console.error('Could not load data:', err)
    return null
  }
}

const main = async () => {
  const data = await fetchData('https://jsonplaceholder.typicode.com/todos/1')
  console.log(data)
  // do whatever I want with the data
}

main()

So just as food for thought, three options that don’t require fetch at all:

  1. Use environment variables
  2. Just import the JSON directly
  3. Use JS instead of JSON and import that

1 requires a build process, 2 will only [currently] work without a build process in Chrome and Edge, 3 will work in any current browser.

2 and 3 rely on use of modules.

For first option you would have the set of values currently in your JSON config stored as environment variables. They are interpolated into your codebase, at build time you tell the build tool which set of vars you’re using, code builds with that config.


For second option, if you’re using modules then you can just do

import myjson from "./myjson" assert { type: "json" };

Or

const myjson = await import("./myjson", { assert: { type: "json" }});

In above cases, myjson is just a JS object, same as any other JS module import.

Note that importing JSON works out-of-the-box in Chrome. Firefox is behind a flag, should be in v soon. Safari needs to wait until next OSX/iOS release. However, there’s a build process then this can be transpiled.


For third option, you can also use a JS file rather than a JSON file, ensure it exports the thing you want, and import that, eg

export myconfigs = {
  foo: 1,
  bar: 2,
}

Then

import {  myconfigs } from "./myconfigs.js";

// ...then use them in the code

Or

const { myconfigs } = await import("./myconfigs.js");

// ...then use them in the code

Just as an aside with current fetch based solution, can just do this at the top of the file

const { someUrl, someToken, someEmail, someNumber } = await fetch("./somejson").then((response) => response.json());

// ...then use someUrl, someToken etc in your code

So as the first line in the file, just fetch and parse the values from the JSON file.

I am assuming that if the values you’re extracting from the JSON aren’t there then the code won’t work, so I’m not sure you really need any error handling. It should just explode if something fails

OK this is quite sophisticated for me, I’m not familiar with async and await, I know what they mean/do in theory, but haven’t used them so far nor do I know the correct syntax. I see 3 await calls and 2 async calls, I need some more learning.

If I add your code, I get the following

console.log(data) // [object Object]
console.log(data.someUrl) // undefined
console.log(data[someUrl]) // Uncaught (in promise) ReferenceError: someUrl is not defined
console.log(data[‘someUrl’]) // undefined

I understand that () => {…} is the callback function?

async/await is just syntactic sugar for a Promise. Instead of wrapping what you want to happen after the Promise in a then block, just just use the await on the Promise.

I see 3 await calls and 2 async calls, I need some more learning.

They are not calls. You tell JS that the function will be dealing with async and you put await in front of anything that returns a Promise that you want to wait on and evaluate. There is nothing you can do with async/await that you can’t do with nested then methods and various Promise tricks - it’s just much, much easier to read.

If I add your code, I get the following…

But where are you adding it?

console.log(data) // [object Object]

That means that it is too big to show? Try:

console.log(JSON.stringify(data, null, 2))

console.log(data[someUrl]) // Uncaught (in promise) ReferenceError: someUrl is not defined

This assumes that there is a variable called “someUrl”.

I understand that () => {…} is the callback function?

I don’t understand what you mean by the callback function. I don’t even think it is a callback function. I don’t see anything in there I would term a callback function. Did you mean this:

const main = async () => {

That is just defining an async arrow function. I could have also defined it as:

async function main() {

But I wouldn’t call that a callback function - it’s not a function being passed into a second function to be used to complete a task in that second function. True, a lot of simple callbacks are written as arrow functions, but they don’t have to be and they can be used elsewhere.

thanks for your suggestions

what is that? installed via npm on terminal? that’s overkill, the project is otherwise mostly done. This is just one little thing I want to add.

what does that even mean? :sweat_smile:

You lost me. I feel I’ve been living under a rock. I might have to add, I’m a designer, web designer and recently self-taught developer. When did all this get so complicated? How do I catch up?

import sounds easy to use, if you can use it, with a lot of ifs and buts though.

I considered option 3 before myself, but if I want to use these variables in php as well, I reckon it needs to be JSON.

I add it right inside the const main = async () => {…} code block

this logs the json from the provided url alright, not my local file though.

OK, I thought these arrow functions are always the simple syntax for callback functions

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.