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
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
Once that's run, you can bootstrap a houdini project using the command line tool:
npx houdini init
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')
}
}
}
}
}
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 />
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>
Next, execute the generate
command to create the files needed for your query:
npx houdini generate
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>
...
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)
Just tested: perfect, great !
Definetly looking forward to see how subscriptions work and SSR with houdini
Thank you!
I got
$data
isundefined
. Fixed it withAwesome!
Thanks! Glad you liked it :)
I get
is outside of Vite serving allow list.???
Update your Vite config like this:
Thanks, now it works
Can this be used with any graphql server implementation? Such as Apollo?
yep! It works with any GraphQL API