Reputation: 143
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).
Upvotes: 10
Views: 7889
Reputation: 41
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.
Upvotes: 3
Reputation: 143
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.
Upvotes: 2
Reputation: 29605
Write the JSON file into the static
folder, as static/data/videoslist.json
.
Upvotes: 5
Reputation: 16411
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
Upvotes: 2