Getting Started โ
This short guide will take you from basic usage to use of the optional document builder.
Node with pnpm is used here but any package manager as well as Deno and Bun users should be able to follow along.
๐ก Setup Your Project โ
If you don't already have a project, create one:
pnpm init
We're going to use TypeScript for this project but you don't have to.
tsx
makes running TypeScript files easy.@tsconfig/strictest
makes having strict TypeScript settings easy.
pnpm add --save-dev typescript tsx @tsconfig/strictest
touch tsconfig.json main.ts
{
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": {
"module": "Node16",
"moduleResolution": "Node16"
}
}
๐ฆ Install Graffle โ
Graffle is still in development so there is no stable release to install yet. Use the next
distribution tag to find the latest pre-release.
Graffle has a peer dependency on graphql
so you will need to install that too.
pnpm add graffle@next graphql
๐ Verify Project Configuration โ
Graffle is an ESM only package built around package exports
. This imposes a few requirements on your project configuration.
- One of:
- Your project is using ESM (
"type": "module"
). - Your project is using CJS with
node@^22.12.0
ornode@^20.17
with--experimental-require-module
.
- Your project is using ESM (
- If you are using TypeScript:
- If you are using TypeScript your
tsconfig.json
must setmodule
andmoduleResolution
toNode16
orBundler
. Otherwise TypeScript will not be able to find the types when you attempt to import entrypoints fromgraffle
. - Your TypeScript version must be
typescript@^4.9
.
- If you are using TypeScript your
- If you are using React Native:
- Do this to enable support for package
exports
.
- Do this to enable support for package
๐ Send Your First Document โ
Now you're ready to send your first GraphQL document. We'll use a publicly available GraphQL API (Thanks Trevor!). Create a Graffle instance and then use it to send a document.
// @filename: main.ts
import { Graffle } from 'graffle'
const graffle = Graffle
.create()
.transport({
url: 'https://countries.trevorblades.com/graphql',
})
const data = await graffle.gql`
query myQuery ($filter: [String!]) {
countries (filter: { name: { in: $filter } }) {
name
continent {
name
}
}
}
`
.send({ filter: [`Canada`, `Germany`, `Japan`] })
console.log(data)
{
"countries": [
{ "name": "Canada", "continent": { "name": "North America" } },
{ "name": "Germany", "continent": { "name": "Europe" } },
{ "name": "Japan", "continent": { "name": "Asia" } }
]
}
๐ง Meet Document Builder โ
You could stop here if you want, but if you're curious about Graffle's document builder (aka. "query builder") continue on!
The document builder is an alternative to the GraphQL document syntax. With it, you express GraphQL documents in JavaScript. And thanks to Graffle's powerful types all inputs (GraphQL arguments) and outputs (execution results) are type safe โจ. The document builder is a Graffle extension. By not hardcoding this feature into core, we keep Graffle lean and bundle sizes smaller for users that are not leveraging it.
To access the document builder you have to use the extension and perform a code generation step. Let's begin with code generation. When you installed graffle
you also gained access to a command line interface (CLI) in your project. Use it now to generate code that will augment your client.
pnpm graffle --schema https://countries.trevorblades.com/graphql
You will see a directory named graffle
has been created in the current working directory. The generated code within augments a global TypeScript type that Graffle's static code knows about. The result is the illusion of new client methods available to you but in reality its actually just a Proxy instance that was there all along, dynamically receiving all the property requests. In other words you have just generated some code but nothing about the runtime has actually changed. Feel free to poke around at the files. Notice how the vast majority is just types (we can ignore the runtime parts for now).
|
|- graffle/
| |- ...
|
Note let's use the extension and rewrite our GraphQL document using the document builder. You should notice some new client methods in your IDE like .document
and .query.countries
.
// todo twoslash
// @filename: main.ts
import { Graffle } from 'graffle'
import { DocumentBuilder } from 'graffle/extensions/document-builder'
const graffle = Graffle
.create()
.transport({
url: 'https://countries.trevorblades.com/graphql',
})
.use(DocumentBuilder())
const data = await graffle.document({
query: {
myQuery: {
countries: {
$: {
filter: { name: { in: [`Canada`, `Germany`, `Japan`] } },
},
name: true,
continent: {
name: true,
},
},
},
},
}).send()
console.log(data)
// ^?
{
"countries": [
{ "name": "Canada", "continent": { "name": "North America" } },
{ "name": "Germany", "continent": { "name": "Europe" } },
{ "name": "Japan", "continent": { "name": "Asia" } }
]
}
๐งน Simplify With Root Fields โ
The .document
method is 1:1 with the GraphQL document syntax in regards to what it can express. Graffle also gives you dedicated methods for each root field (fields on Query
, Mutation
, and Subscription
) which can be simpler depending on your use-case. Let's refactor our code with it.
// ...
const data = await graffle.document.query.countries({
$: { filter: { name: { in: [`Canada`, `Germany`, `Japan`] } } },
name: true,
continent: {
name: true,
},
})
// ...
๐งฐ Utilities โ
Graffle gives you utilities beyond the direct client itself. For example you can build up reusable selection sets:
import { Graffle } from './graffle/__.js'
const ContinentSelection = Graffle.Select.Continent({ name: true })
import { Select } from './graffle/_.js'
const ContinentSelection = Select.Continent({ name: true })
You can also do the same thing at the type level which can sometimes be handy when you want to define data types based on selection sets.
import { type Graffle } from './graffle/__.js'
type Continent = Graffle.Select.Continent<{ name: true }>
import { type Select } from './graffle/_.js'
type Continent = Select.Continent<{ name: true }>
Refer to the Selection Sets Example for more detail about type level features the generator provides you.
๐๏ธ Conclusion โ
We hope this introductory tutorial has been useful for you. Graffle has many more features to discover, such as extensions, anyware, custom scalar support, how every GraphQL query language feature is realized in the document builder, and more. Peruse these docs to learn about it all.
Thanks for taking time to learn Graffle. Let us know how your experience goes as your begin to build your projects with it!