MAIS AMOR POR FAVOR

Using fetch with SvelteKit: Call APIs and Server Endpoints

Using fetch with SvelteKit

Using fetch with SvelteKit: Call APIs and Server Endpoints

SHARE:

🖥 The fetch API and SvelteKit

Using fetch with SvelteKit, you can pull data from your server endpoints ahead of rendering a page or contact external server endpoints from your own server code. As well as that you can contact external server endpoints from client code, perhaps to submit form data or even to get fresh data for refreshing the user interface. In this video we break down those three main use cases and also look at how fetch HTTP requests differ from axios calls. fetch is baked in to SvelteKit so I like to use it in SvelteKit projects.

Hopefully this video will spark some ideas for a new SvelteKit pet project. If that is what you have in mind, listen out for the more in-depth tutorials mentioned in the video. It is my intention that these give you some inspiration, providing launch sites you might base your new projects off. Anyway, I hope this topic is one you will find interesting and look forward to hearing all the questions it generates.

📹 Using fetch with SvelteKit: Video

Using fetch with SvelteKit: Call APIs and Server Endpoints

🗳️ Poll

Are you most familiar with using axios, fetch or jQuery.ajax?
Voting reveals latest results.

🖥 Using fetch with SvelteKit: Code

Frontend: Calling fetch in a SvelteKit Load function

src/routes/index.svelte
svelte
1<script context="module">
2 export const load = async ({ fetch }) => {
3 try {
4 const response = await fetch('/query/fx-rates.json', {
5 method: 'POST',
6 credentials: 'same-origin',
7 headers: {
8 'Content-Type': 'application/json'
9 },
10 body: JSON.stringify({ currencies: ['CAD', 'GBP', 'IDR', 'INR', 'USD'] })
11 });
12 return {
13 props: { ...(await response.json()) }
14 };
15 } catch (error) {
16 console.error(`Error in load function for /: ${error}`);
17 }
18 };
19</script>

Calling fetch in a SvelteKit Server Endpoint

src/routes/query/fx-rates.json.ts
typescript
1import type { Query, QueryLatestArgs } from '$lib/generated/graphql';
2import type { Request } from '@sveltejs/kit';
3
4export async function post(
5 request: Request & { body: { currencies: string[] } }
6): Promise<{ body: string } | { error: string; status: number }> {
7 try {
8 const { currencies = ['CAD', 'GBP', 'IDR', 'INR', 'USD'] } = request.body;
9
10 const query = `
11 query latestQuery(
12 $baseCurrency: String = "EUR"
13 $quoteCurrencies: [String!]
14 ) {
15 latest(
16 baseCurrency: $baseCurrency
17 quoteCurrencies: $quoteCurrencies
18 ) {
19 baseCurrency
20 quoteCurrency
21 date
22 quote
23 }
24 }
25 `;
26
27 const variables: QueryLatestArgs = {
28 baseCurrency: 'EUR',
29 quoteCurrencies: currencies
30 };
31
32 const response = await fetch('https://swop.cx/graphql', {
33 method: 'POST',
34 headers: {
35 'Content-Type': 'application/json',
36 Authorization: `ApiKey ${process.env['SWOP_API_KEY']}`
37 },
38 body: JSON.stringify({
39 query,
40 variables
41 })
42 });
43 const data: { data: Query } = await response.json();
44
45 return {
46 body: JSON.stringify({ ...data })
47 };
48 } catch (err) {
49 const error = `Error in /query/fx-rates.json.ts: ${err}`;
50 console.error(error);
51 return {
52 status: 500,
53 error
54 };
55 }
56}

Frontend: Using a Svelte Store to Update User Interface with fetch Data

src/routes/index.svelte
svelte
21<script lang="ts">
22 import '@fontsource/source-sans-pro';
23 import rates from '$lib/shared/stores/rates';
24 import type { Query } from '$lib/generated/graphql';
25 export let data: Query;
26
27 rates.set(data.latest);
28 let newCurrency = '';
29 let submitting = false;
30
31 async function handleSubmit() {
32 try {
33 submitting = true;
34 const response = await fetch('/query/fx-rates.json', {
35 method: 'POST',
36 credentials: 'same-origin',
37 headers: {
38 'Content-Type': 'application/json'
39 },
40 body: JSON.stringify({ currencies: [newCurrency] })
41 });
42 const responseData: { data: Query } = await response.json();
43 const rate = responseData.data.latest[0];
44 submitting = false;
45 rates.set([...$rates, rate]);
46 newCurrency = '';
47 } catch (error) {
48 console.error(`Error in handleSubmit function on /: ${error}`);
49 }
50 }
51</script>
52
53<main class="container">
54 <div class="heading">
55 <h1>FX Rates</h1>
56 </div>
57 <ul class="content">
58 {#each $rates as { baseCurrency, quoteCurrency, date, quote }}
59 <li>
60 <h2>{`${baseCurrency}\${quoteCurrency}`}</h2>
61 <dl>
62 <dt>
63 {`1 ${baseCurrency}`}
64 </dt>
65 <dd>
66 <span class="rate">
67 {quote.toFixed(2)}
68 {quoteCurrency}
69 </span>
70 <details><summary>More information...</summary>Date: {date}</details>
71 </dd>
72 </dl>
73 </li>
74 {/each}
75 </ul>
76
77 <form on:submit|preventDefault={handleSubmit}>
78 <span class="screen-reader-text"
79 ><label for="additional-currency">Additional Currency</label></span
80 >
81 <input
82 bind:value={newCurrency}
83 required
84 id="additional-currency"
85 placeholder="AUD"
86 title="Add another currency"
87 type="text"
88 />
89 <button type="submit" disabled={submitting}>Add currency</button>
90 </form>
91</main>

Frontend: Using a Svelte await Block to Update User Interface with fetch Data

narcissus/demos/narcissus-sveltekit/src/lib/components/PostViewsLikes.svelte
shell
1<script lang="ts">
2 import website from '$lib/config/website';
3 import PostViewsLikesPure from '$lib/components/PostViewsLikesPure.svelte';
4
5 export let likes: number;
6 export let views: number;
7 export let slug: string;
8 export let comments: number;
9 export let containerClass: string = undefined;
10 export let contentClass: string = undefined;
11 export let interactive: boolean = true;
12
13 const { workerUrl } = website;
14
15 async function getViewsLikes() {
16 try {
17 const url = `${workerUrl}/post/data`;
18 const response = await fetch(url, {
19 method: 'POST',
20 credentials: 'same-origin',
21 headers: {
22 'Content-Type': 'application/json',
23 },
24 body: JSON.stringify({
25 slug,
26 }),
27 });
28 return response.json();
29 } catch (error) {
30 console.error(`Error in getViewsLikes: ${error}`);
31 }
32 }
33
34 const likesPromise = getViewsLikes() ?? { likes, views };
35</script>
36
37{#await likesPromise}
38 <PostViewsLikesPure {containerClass} {contentClass} {slug} {likes} {views} {comments} />
39{:then data}
40 <PostViewsLikesPure
41 {containerClass}
42 {contentClass}
43 {slug}
44 likes={data?.likes ?? likes}
45 views={data?.views ?? views}
46 comments={data?.comments.length ?? comments}
47 {interactive}
48 />
49{:catch}
50 <PostViewsLikesPure {containerClass} {contentClass} {slug} {likes} {views} {comments} />
51{/await}

Videos, Tutorials and Sample Code

Docs

Reaching Out

🏁 Using fetch with SvelteKit: Summary

How do you use fetch in SvelteKit client page load functions?

SvelteKit runs load functions before rendering a client page. That makes them the ideal place to pull in data from your server endpoint in many cases. Although the module which loads functions works differently to typical browser JavaScript blocks, fetch is still available. You can desctructure fetch from the object passed to load function's first argument. Take a look at video for a real-life use case.

How is the fetch API different to using axios?

It might make sense to use fetch over axios in SvelteKit projects as fetch is already included. That said, there are a few differences, although for the most part, axios and fetch work in the same way. With axios, you can send objects in the data field and they are converted to a string automatically by the package, ready for including in the request. With fetch you just wrap your object in a JSON.stringify() call and it goes in the body field, rather than data. A second difference is in accessing JSON received in a response. With axios the object is accessible via the data field on the resolved promised that is returned by the initial axios call. With fetch you access the data by calling a json() method on the resolved promise. That method call itself returns a new promise, so be sure to let it resolve before attempting to read the embedded JSON.

How do await blocks work in Svelte?

In Svelte, await blocks are a tidy little way of displaying data recived in a promise. Promises are used when a result cannot be returned immediately. A classic example is fetching data from an external API which is not notmally immediate. The promise is kind of a placeholder returned intially while the requested data is still on its way. The await block in Svelte has three arms. The first it for what you display while you wait for the promise to resolve. You might show a loading indicator or alternatively any available, albeit, stale data. The second arm is used for the content which you want to show once the promise resolves. As you would expect, you can access the promise result here and use it in whatever you render. Finally, we have an optional catch arm. We use this when the promise fails to resolve. You might show a “try again later” message or just the previously available data.

🙏🏽 Feedback

If you have found this video useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention so I can see what you did. Finally be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram . Also, see further ways to get in touch with Rodney Lab. I post regularly on SvelteKit as well as Search Engine Optimisation among other topics. Also subscribe to the newsletter to keep up-to-date with our latest projects.