DEV Community

Cover image for Building an Application with GraphQL and SvelteKit
Alec Aivazis
Alec Aivazis

Posted on

Building an Application with GraphQL and SvelteKit

So, you've decided to build an application with two of the most hyped projects in our community. After browsing the internet for a bit, you've probably ran into various posts showing how to send a query in Kit's load and use it to populate the cache driving one of the more common GraphQL libraries. If you're like me, it probably left you with a bit of an unsatisfying feeling. GraphQL was supposed to reduce the amount of boilerplate necessary to build a user interface, right? Surely there's a way to pull this off without all that ceremony. Well, in this blog post I'll introduce you to houdini, a new GraphQL client I've been working on that's built for SvelteKit. Hopefully by the end of this you'll agree that it dramatically reduces the overhead of building a GraphQL application with SvelteKit.

Getting Started

We're going to be using the Rick and Morty API to build a gallery of characters from the popular television show. Let's begin by starting a normal SvelteKit project:

npm init svelte@next rick-and-morty && \
cd rick-and-morty && \
npm install
Enter fullscreen mode Exit fullscreen mode

You should select the Skeleton project option and the rest is up to you. Houdini fully supports typescript but you don't have to worry about that now if you don't want to. Next, install houdini and its preprocessor (more on that later):

npm install --save houdini houdini-preprocess
Enter fullscreen mode Exit fullscreen mode

Once that's run, you can bootstrap a houdini project using the command line tool:

npx houdini init
Enter fullscreen mode Exit fullscreen mode

When prompted for the API's address, enter https://rickandmortyapi.com/graphql and choose the SvelteKit option when it asks you to choose a framework. You can use the default answers for the rest of the questions (just press enter).

The only thing that's left is to link our application to houdini's runtime. Similar to how Svelte compiles our components, houdini shifts what is traditionally handled by a bloated runtime to a compile step and generates a lean GraphQL layer for your application. In order to use the generated runtime, we need to do two things. First, add the following to svelte.config.js:

import path from 'path'
import houdini from 'houdini-preprocess'

export default {
    // ...

    preprocess: [houdini()],

    kit: {
        vite: {
            resolve: {
                alias: {
                    $houdini: path.resolve('.', '$houdini')
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And finally, create a file at src/routes/__layout.svelte with the following contents. Note, there are two _ in the file name.

<script context="module">
    import { setEnvironment } from '$houdini'
    import environment from '../environment'

    setEnvironment(environment)
</script>

<slot />
Enter fullscreen mode Exit fullscreen mode

Fetching Data

Okay, now that we've set the project up, we can start querying the API. Update src/routes/index.svelte with the following content. Keep in mind that vite's hot reloading will complain about missing files until you compile the runtime:

<!-- src/routes/index.svelte -->

<script>
    import { query, graphql } from '$houdini'

    const { data } = query(graphql`
        query AllCharacters { 
            characters { 
                results { 
                    name
                    id
                    image
                }
            } 
        }
    `) 

</script>

<h1>The World of Rick and Morty</h1>
<main>
    {#each $data.characters.results as character (character.id) }
        <section style={`background-image: url(${character.image})`}>
            <h2>{character.name}</h2>
        </section>
    {/each}
</main>

<style>
    h1, h2 { 
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }

    main { 
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        grid-template-rows: repeat(4, 200px);
        row-gap: 10px;
        column-gap: 10px;
    }

    section { 
        position: relative;
        background-size: cover;
    }

    h2 { 
        display: none;
        position: absolute;
        bottom: 0px;
        margin: 0px;
        padding: 10px;
        background: rgba(255, 255, 255, .5);
        width: 100%;
        font-weight: bold;
    }

    section:hover > h2 { 
        display: block;
    }
</style>
Enter fullscreen mode Exit fullscreen mode

Next, execute the generate command to create the files needed for your query:

npx houdini generate
Enter fullscreen mode Exit fullscreen mode

And that's it! If you haven't already, start the SvelteKit dev server with npm run dev and navigate to http://localhost:3000.

Notice there was no need to write your own load function. The only thing you had to do was write the query and then generate the runtime. One important thing to keep in mind is that every time you change your query, you will have to run the same generate command for things to take effect.

So happened to load?

That's where the preprocessor comes in. One of its jobs is to move the actual request logic into a load function. You can think of the above code as roughly equivalent to:

<script context="module">
    export async load({fetch}) {
        return { 
            props: {
                _data: await fetch({
                    text: `
                        query AllCharacters {
                            characters { 
                                results { 
                                    name
                                    id
                                    image
                                }
                            } 
                        }
                    `
                })
            }
        }
    }
</script>

<script>
    export let _data

    const data = readable(_data, /* ... */)
</script>

...
Enter fullscreen mode Exit fullscreen mode

That's it for now!

In this post, we setup a project with SvelteKit and houdini, created a single page driven by a GraphQL query, and generated the runtime necessary for the application to run.

I wanted to keep this short and sweet to show how easy it is to get something going but Houdini can do a lot more than just fire single queries. If you want to find out more, head over to the project page on Github. That's currently the best place to go for more information. If you would like to read an in-depth series of posts that covers more of houdini's features (fragments, mutations, subscriptions, pagination, etc), let me know in the comments!

Top comments (10)

Collapse
 
geetee profile image
GeeTee

Just tested: perfect, great !

Collapse
 
gevera profile image
Denis Donici

Definetly looking forward to see how subscriptions work and SSR with houdini

Collapse
 
draylegend profile image
Vladimir Drayling

Thank you!

I got $data is undefined. Fixed it with

{#if $data}
    {#each $data.characters.results as character (character.id)}
        <section style={`background-image: url(${character.image})`}>
            <h2>{character.name}</h2>
        </section>
    {/each}
{:else}
    loading
{/if}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
pixelmund profile image
Julian Sigmund

Awesome!

Collapse
 
alecaivazis profile image
Alec Aivazis

Thanks! Glad you liked it :)

Collapse
 
jiftuq profile image
chris

I get
is outside of Vite serving allow list.???

Collapse
 
spences10 profile image
Scott Spence • Edited

Update your Vite config like this:

vite: {
  resolve: {
    alias: {
      $houdini: path.resolve('.', '$houdini'),
    },
  },
  server: {
    fs: {
      // Allow serving files from one level up to the project root
      allow: ['..'],
    },
  },
},
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jiftuq profile image
chris

Thanks, now it works

Collapse
 
delanyoyoko profile image
delanyo agbenyo

Can this be used with any graphql server implementation? Such as Apollo?

Collapse
 
alecaivazis profile image
Alec Aivazis

yep! It works with any GraphQL API