Introduction to Data Loading in SvelteKit
All right then, so far we've seen how to create pages, nested routes, reusable components, and layout files as well. Next up, I want to bring external data into the party because sometimes our applications need to reach out to an API endpoint or maybe a database to fetch some data and then inject that data into component templates so we can see it on the page. So where would we do this? Where would we fetch the data?
Well, the best place to do is inside a separate script tag in whatever page component needs the data. For example, I might want to list out a bunch of gaming guides in the guides index page. So what I do is create a new script tag inside this guides index component, and it's inside this script tag that we go out and fetch the data we need. And this script tag needs to have an attribute called context and that's equal to a value of module.
Now, this script tag would be in addition to the script tag you might already have in your component, and it's a special script as marked by this context attribute. This is how Svelte distinguishes between the two. So it's inside this one with a context attribute equal to module that would fetch any data that's needed for this component.
The load Function and Server-Side Fetching
Now, inside this script, we have a special function called load, and it's an asynchronous function, and it must be called load. This is a special SvelteKit function, and we use this function to fetch any data, and SvelteKit can run this function automatically to go out and fetch any data that's needed for this component.
So this function load takes in an argument automatically, which is a context object, and on that context object is a few different things. One of those things is the fetch function because out of the box, the fetch API is meant for the browser. Now, this context object exposes it for us on the server, too, so that we can use it inside this load function, because this script can run on the server to fetch the data so it can pre-render our templates. So we need that fetch API, if you like, exposed to us so we can use it, otherwise it'd be an error because normally you can't run the fetch API on the server, right?
So, this script can also run in the browser as well, but we're going to talk more about that later on. But anyway, down here, if I wanted to use the fetch function, I could just say context.fetch to invoke that fetch function and go and fetch some resource. But instead, what I'm going to do is just destructure it up here directly from the context arguments, and then if I wanted to, I could just invoke it inside the function by saying fetch like so.
Fetching Data from a Fake API
So all we need to do inside this function then is fetch some data and then return it. So to fetch the data, we're going to be using something called JSON Placeholder, which is a fake API for testing and prototyping. So it gives us a load of different endpoints that we can use to fetch some dummy data essentially. So I'm going to leave the link to this website down below, and if we scroll down here, we're going to see a lot of different endpoints that we can use for different resources. So say for example, I'm going to use this posts resource. The endpoint for this is this thing up here, and you can see all of this JSON data right here. So each post is an object, and for each post we have a title, body, id, and a user id. Now, if we want to get all the posts, we'd use this endpoint. If we want a single post, we'd say forward slash and then the ID of the post, for example, this one, ID of three. So if I place that in and press enter, we just get back that one single post. All right, so this is the endpoint that we're going to use for our project.
So what I'm going to do is place inside the fetch function this endpoint as a string. Now also, since this is an asynchronous function, I can await this, so I'll place await in front of it, not in capitals, await like so. And then I'm going to store the response in a constant. So I'm going to say const and I'll call it res for response and set it equal to this. So this response object now has a JSON method on it which we can call, and that will pass the response into an object for us that we can use. So what I'm going to do is say const guides and set that equal to await again, because the json method is asynchronous, and I'm going to say response.json like so. So now guides will be an array of objects that we can use inside our templates.
Returning Props and Handling Errors
But how do we first of all get this data, this guides stuff, and use it inside here? Because just because we fetched it right here, we can't automatically use it in the template. What we have to do is we need to return the guides as a prop which we then accept as a prop inside this other script. So first of all, I want to check that the response is okay. Now, this response object has an ok property on it, and it's true if the response is okay and we have that data, and it's false if it's not okay, when there's been something wrong.
So I'm going to say if (response.ok). Then we're going to do something. Now, the thing we're going to do is return an object, and inside this object is a props property which is also an object. And now we can have as many props as we want injected into our component, and they are just different properties. So I could have a hello prop if I wanted to, and that could be anything, it could just be a string, "hello there". Now, I don't want to do this. Instead, what I want is a guides prop and that is going to be equal to the guide up here, like so. Now, since this and this is named the same, we can shorten this, and this does exactly the same thing.
All right, so we're returning the guides as a prop, but that's only if the response is okay. If the response is not okay, it's going to carry on, and it's going to return this object instead, whereby we have a status property which is going to be the response.status, and that's probably going to be a 404 response if this is incorrect, this endpoint or something. And then down here, we also have an error property that we can return. That's going to be a new Error, and inside here, we'll just say, "could not fetch the guide".
Now, we're going to talk more about error pages and errors later on, but for now, know that only if the response is okay are we returning this object with a props property where we pass the guides as a prop. If the response is not okay, something's wrong, we return a different kind of object where we have a status property, which is the status property on the response object, and also an error property as well. And we've made this error up, "could not fetch the guides." All right.
Consuming Props and Rendering the Data
Now that if everything is okay and we return these props, we can accept this prop inside this script, much like we did inside the other component over here. So you know, inside the title, we said export in front of the name of the prop, title. We do something similar over here inside this script. We just say export let and then whatever the prop is called, in our case it's called guides right here because that's what we called it.
So, now we can use the guides inside this template. So we could cycle through them and then we could output an li tag for each one instead of hard-coding these li tags. So that's what I'm going to do now. To cycle through an array of items in Svelte, we say curly braces, then hash, then each, and then what we want to cycle through. We want to cycle through the guides. And then what we refer to each one as, I'm going to call it a guide, but you can call it g, doesn't really matter. Now, down here we need to end the each, and we do that inside curly braces again: forward slash each, like so.
So what this is saying is, look, cycle through the guides, and each time you cycle through those refer to the one you're currently iterating on as a guide. And then we can use this object inside the each block. So I could output an li tag for each of the guides, and then inside that an anchor tag where the href for now is just going to be forward slash, but we'll come to that later on and change it for each guide. And then we can output the guide title, so guide.title. Remember, the title was a property on the guides from the JSON. All right, so now we're cycling through the guides that we get back up here, and for each one of the guides, we output an li tag and inside that, an anchor tag, and then the title of the guide. So fingers crossed, this should now all work.
Final Result and Next Steps
All right, so I'm on the homepage currently, but hopefully when I click 'View Guides', we're going to see all of those guides listed on the guides components and not some gigantic error because I've mucked something up. So View Guides... yep, and we see all of them. Awesome. And there's a hell of a lot of them, 100 in total, I think. So these are all coming from JSON Placeholder.
So again, we fetch data by using the load function inside an extra script tag at the top with a context attribute of module, and we return an object with all of the props we want to inject into our component. And this has all worked. Right now, at the minute when we click on one of these titles, it's just going to go to the home page, and that is true of all of them because we've hard-coded the href attribute on the anchor tags to be just a forward slash, which goes to the homepage.
Now, what I want to do is create some kind of details page for each one of these individual things right here, so that when we click on them, it goes to the details page for that particular guide. And we'll see how to do that later on. But just first, I want to quickly talk about server-side code versus client-side code because these scripts right here can actually run on the server and the client as well, in the browser. So I want to talk about why that's important in the next lesson.