Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sapper/Svelte: how to fetch a local json file to retrieve data

In my sapper app, I have some data stored in a json file at src/data/videoslist.json, an array of objects in json format.

I need to retrive the data in my index page to pass it to the component. Here's my code at the top of src/routes/index.svelte

<script context="module">
    export async function preload() {
        const response = await this.fetch('../data/videoslist.json');
        const responseJson = await response.json();
        return {
            videos: responseJson
        }
    }
</script>

I get an error 500

invalid json response body at http://127.0.0.1:3000/data/videoslist.json reason: Unexpected token < in JSON at position 0

The file is pure json, nothing else. The unexpected token < makes me think a 404 is returned instead of the file.

Do you know what I get wrong ? I tried so many paths variations wit ../ ./ or moving the file to the route folder, but nothing works.

PS: I'm still a newbie with js and framework stuff, I may have missed something very basic for someone who knows better :) (like you can't retrieve a local file with fetch).

like image 648
Kris Avatar asked May 17 '20 16:05

Kris


People also ask

How do I access local JSON file?

Use the fetch() Function to Load JSON Files in JavaScript This function fetches the file from the path where it is saved and then returns the file as the response in the console. data . This function is only suitable for working in the web-based environment as the fetch API works only in that environment.

How can we fetch data from JSON file?

The jQuery code uses getJSON() method to fetch the data from the file's location using an AJAX HTTP GET request. It takes two arguments. One is the location of the JSON file and the other is the function containing the JSON data. The each() function is used to iterate through all the objects in the array.

How do I import a JSON file into svelte?

SvelteKit uses vite tooling which lets you import JSON files in addition to, for example all file in a folder matching a pattern (glob imports). Unlike glob imports, there are no promises involved and you can import an entire JSON file as a default import using the regular syntax: import data from '../data. json'.


4 Answers

Write the JSON file into the static folder, as static/data/videoslist.json.

like image 183
Rich Harris Avatar answered Nov 07 '22 16:11

Rich Harris


I've noticed that with the following:

<script context="module">
    export async function preload({ params: { id } }) {
       return await (await this.fetch(`/route/${id}/details.json`)).json();
    });
</script>

...the SSR code will attempt to load https://127.0.0.1/route/id/details.json - which fails on my hosting. If I specify a fully-qualified absolute URL (externally accessible), e.g.

this.fetch(`https://hostname.tld/route/${id}/details.json`)

..it works fine. I have a details.json.js server route set up, which is working as expected when the URL is accessed directly via https://hostname.tld/route/id/details.json

Sapper evidently runs the same code on the client after the server 500, so the page still works, but it's somewhat confusing.

I had a similar issue with relative paths in preload scripts due to the hosting provider blocking with lack of referrer (resulting in a 403), which can be mitigated with:

this.fetch(`/route/${id}/details.json`, { referrerPolicy: "origin" })

...however, this doesn't seem to help in this instance.

I can obviously just change the URL to be absolute, but I'd rather not tie this to the host, screw up local dev, and evidently force the SSR code to leave the local network. I guess I'm unclear how server-side fetch works to localhost, so may not be a sapper-specific issue.

N.B. I can utilise "host" from the preload page argument to construct an absolute URL thus (must be http not https):

<script context="module"> 
   export async function preload({ host, params: { id } }) { 
      return await (await this.fetch(`http://{host}/route/${id}/details.json`)).json(); 
   });
</script>

...and it works on the hosting - but fear it isn't intuitive, and not as the documentation suggests.


like image 25
Tom Pereira Avatar answered Nov 07 '22 17:11

Tom Pereira


In Sapper, when you try to fetch a json file that it actually looks for a route/file with the name videoslist.json.js you have to make that file, and have it return the json. You can find an example of that in the docs here: https://sapper.svelte.dev/docs#Server_routes

like image 27
Stephane Vanraes Avatar answered Nov 07 '22 16:11

Stephane Vanraes


Rich's solution works very well.

I just moved the json file into the static folder and the following code works now.

<script context="module">
    export async function preload() {
        const response = await this.fetch('videoslist.json');
        const responseJson = await response.json();
        return {
            videos: responseJson
        }
    }
</script>

This solutions gives direct acces to the file without dealing with server routing and paths.

like image 44
Kris Avatar answered Nov 07 '22 17:11

Kris