Skip to content

Commit

Permalink
chore(docs): reorganize overview content
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt committed Sep 9, 2024
1 parent 417d6e9 commit 593cd64
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 149 deletions.
10 changes: 4 additions & 6 deletions website/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,9 @@ export default defineConfig({
link: '/guides/overview/getting-started-generated',
}],
},
{
text: 'Generation <span title="Requires generation" style="font-size:1.75em;line-height:0;">⩕</span>',
link: '/guides/overview/generation',
},
{ text: 'Output', link: '/guides/configuration/output' },
{ text: 'Anyware', link: '/guides/configuration/anyware' },

{ text: 'Output', link: '/guides/overview/output' },
{ text: 'Anyware', link: '/guides/overview/anyware' },
],
},
{
Expand Down Expand Up @@ -131,6 +128,7 @@ export default defineConfig({
{ text: 'Schema Errors', link: '/guides/misc/schema-errors' },
{ text: 'Select', link: '/guides/misc/select' },
{ text: 'Extension Authoring', link: '/guides/misc/extension-authoring' },
{ text: 'About Generation', link: '/guides/misc/about-generation' },
],
},
{
Expand Down
6 changes: 6 additions & 0 deletions website/content/_snippets/benefits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
1. A TypeScript first interface for creating and sending requests including method names that reflect the schema.
2. Type-safe request inputs (selection set, directives, etc.).
3. Type-safe request outputs (results) inferred from the input.
4. Automatic encoding and decoding of custom scalars.
5. Type utilities to create TypeScript types based on types in the GraphQL schema.
6. Runtime utilities to create reusable selection sets.
1 change: 0 additions & 1 deletion website/content/guides/configuration/request.md

This file was deleted.

36 changes: 36 additions & 0 deletions website/content/guides/misc/about-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# About Generation

This guide is an overview of using generation. Individual features enabled by generation are discussed in other guides. There is a [practical tutorial in getting started](../overview/getting-started-generated.md). But if you're trying to build a mental model of what Graffle means when it talks about generation or generally want more detail on generation tools, then this guide is for you.

## Benefits

If you haven't read the [introduction](../overview/introduction.md), here is a recap of benefits from generation:

<!--@include: @/_snippets/benefits.md-->

## Architecture

TODO

## CLI

Typically you will use the CLI to generate a client. After installing `graffle` you will have access to a CLI also named `graffle`.

```bash
pnpm add graffle
pnpm graffle --schema '...'
```

The CLI has built in help that you can use to learn about all its inputs.

```bash
pnpm graffle --help
```

## API

If you need to script graffle client generation then you can drop to the underlying Graffle generator API. It is largely one-to-one with the CLI. Use its JSDoc to learn about all its inputs.

```ts
import { generate } from 'graffle/generator'
```
File renamed without changes.
118 changes: 0 additions & 118 deletions website/content/guides/overview/generation.md

This file was deleted.

145 changes: 131 additions & 14 deletions website/content/guides/overview/getting-started-generated.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
# Getting Started <Badge text="generated client" />

The following takes you through a simple example to demonstrate how generation works and what it gives you.

## Install Package

Graffle has a peer dependency on `graphql` so you will need to install that too.
If you don't already have a project, create one:

```sh
pnpm add graffle graphql
pnpm init
```

## Generate Client Lib
Install dependencies. Graffle has a peer dependency on `graphql` so you will need to install that too. To easily run TypeScript we'll install `tsx`.

```sh
pnpm add graffle graphql tsx
```

## Generate Client

Now you have access to the `graffle` command line interface in your project. Use it to generate a client. We will use a simple publicly available GraphQL API for our schema source.

```sh
pnpm graffle --schema https://countries.trevorblades.com/graphql
```

You will see a directory named `graffle` has been created in the current working directory.
You will see a directory named `graffle` has been created in the current working directory. You will import Graffle from here now instead of the static library `graffle`. Note that you still need `graffle` installed as the generated code is just a thin layer of code that still imports from `graffle`.

```
|
Expand All @@ -28,31 +36,114 @@ You will see a directory named `graffle` has been created in the current working
> [!note] Schema Sources
> You can use any GraphQL API that has introspection enabled. Alternatively you can also give a file path to a [GraphQL SDL file](https://todo).
## Create Client
## Instantiate Client

Create a module, import the constructor, and create an instance. As you can see it is extremely minimal. Graffle even defaults the schema URL to what we used during gentime so we can omit it here.
Create a module (e.g. `main.ts`), import the constructor, and create an instance.

```ts twoslash
import { Graffle } from './graffle/__.js'

const graffle = Graffle.create() // [1]
```

Note:

1. The constructor's `schema` parameter that tells the client _where_ to send requests to is optional because the CLI used a URL to introspect the schema at generation time and thus defaults the generated client to use that same URL.

## Starting Raw

Now you're ready to send a request (run e.g. `pnpm tsx main.ts`). Before getting to the generated part though, we'll confirm that the base static client works just as it did without generation:

```ts twoslash
import { Graffle } from './graffle/__.js'
const graffle = Graffle.create()
// ---cut---
const result = await graffle.rawString({
document: `query { continents { name } }`,
})
console.log(result.data)
```

## Send Document
<!-- dprint-ignore -->
```js
{
continents: [
{ name: 'Africa' },
{ name: 'Antarctica' },
{ name: 'Asia' },
{ name: 'Europe' },
{ name: 'North America' },
{ name: 'Oceania' },
{ name: 'South America' },
]
}
```

Great! This is a core principal of Graffle: Generation is _addidative_. You don't need to unlearn anything from the static client.
## Generated Document Method
Now you're ready to send a "document". Your generated client gives you a rich interface reflecting the shape of the schema. Not only does this give you type safety it simplifies the result type (but if you want that envelope back for any reason don't worry, its [just a config away](./todo)).
Now let's try the generated TypeScript interface that reflects our schema. We'll rewrite our query:
```ts twoslash
import { Graffle } from './graffle/__.js'
const graffle = Graffle.create()
// ---cut---
const data /* [2] */ = await graffle
.document({ // [1]
demoQuery: { // Operation name
query: { // Operation
continents: { // Query field selection
name: true, // Continent field selection
},
},
},
})
.run()
```
const graffle = Graffle.create({ schema: 'abc' })
Note:
1. The input is type safe.
2. The results are type safe.
## Generated Query Field Method
The `.document` method we just used allows sending whole GraphQL documents but we can use a more direct interface if we just want `continents` data:
```ts twoslash
import { Graffle } from './graffle/__.js'
const graffle = Graffle.create()
// ---cut---
const continents = await graffle.query.continents({ name: true })
console.log(continents)
```
<!-- dprint-ignore -->
```js
[
{ name: 'Africa' },
{ name: 'Antarctica' },
{ name: 'Asia' },
{ name: 'Europe' },
{ name: 'North America' },
{ name: 'Oceania' },
{ name: 'South America' },
]
```
Simple! Notice that the default output changes here to the `result.data.continents`. In the [Output guide](./output.md) you'll learn how to change this behavior if desired.

## Arguments

Like the rest of GraphQL's features, arguments are modelled into the TypeScript interface. Here's an example of that. Notice the special `$` property. It is an invalid GraphQL field name so Graffle knows it can be safely used for arguments regardless of the design of the schema. Here we reduce the set of all countries to just three.

```ts twoslash
import { Graffle } from './graffle/__.js'
const graffle = Graffle.create()
// ---cut---
const countries = await graffle.query.countries({
$: {
filter: {
name: { in: [`Canada`, `Germany`, `Japan`] },
},
},
$: { filter: { name: { in: [`Canada`, `Germany`, `Japan`] } } },
name: true,
continent: {
name: true,
Expand All @@ -70,3 +161,29 @@ console.log(countries)
{ "name": "Japan", "continent": { "name": "Asia" } }
]
```

## Utilities

Its worth knowing Graffle also gives you utilities beyond the direct client itself. For example you can build up reusable selection sets:

```ts twoslash
// TODO
// import { Select } from './graffle/__.js'
import { Select } from './graffle/modules/Select.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.

```ts twoslash
// TODO
// import { type Select } from './graffle/__.js'
import { type Select } from './graffle/modules/Select.js'
type Continent = Select.Continent<{ name: true }>
```

## Conclusion

There is more to learn (e.g. how directives, unions, interfaces, custom scalars, ... are modelled into the TypeScript interface) but hopefully this has already given you some confidence to go off and start building. Of course feel free to continue digging deeper into more specific feature guides too. Thanks for taking time to learn Graffle and we're excited to see what you'll build!
Loading

0 comments on commit 593cd64

Please sign in to comment.