aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 7f75f7baee66b398f2007126c2c3dd68926ee078 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# @eol/gq

A batteries-included GraphQL toolkit for Deno, wrapping `graphql-js` and `@graphql-tools/schema` with the bits most APIs end up reaching for anyway: a Fetch-compatible HTTP handler, a cached `gql` tag, a `.graphql` file loader, and an embedded GraphiQL UI powered by [`@eeeooolll/graphiql`](https://www.npmjs.com/package/@eeeooolll/graphiql).

## Install

Published on JSR as [`@eol/gq`](https://jsr.io/@eol/gq).

```sh
deno add jsr:@eol/gq
```

Or import directly:

```ts
import { executeSchema, gql, GraphQLHTTP } from "jsr:@eol/gq";
```

## Quick start

```ts
import { executeSchema, gql, GraphQLHTTP } from "@eol/gq";

const schema = executeSchema({
  resolvers: {
    Query: {
      hello: (_, { name }) => `hello, ${name ?? "world"}`
    }
  },
  typeDefs: gql`
    type Query {
      hello(name: String): String
    }
  `
});

Deno.serve(
  { port: 8000 },
  GraphQLHTTP({ graphiql: true, schema })
);
```

Visit `http://localhost:8000` in a browser for GraphiQL, or `POST` a query to the same URL.

## Loading schemas from `.graphql` files

Use `importQL` to read an entry file and resolve its imports into a single SDL string.

### Explicit imports

```graphql
# schema/schema.graphql
# import "./post.graphql"
# import "./user.graphql"

type Query {
  me: User
  posts: [Post!]!
}
```

```ts
import { executeSchema, gql, importQL } from "@eol/gq";

const typeDefs = gql(await importQL("schema/schema.graphql"));
const schema = executeSchema({ resolvers, typeDefs });
```

### Dynamic imports

Drop `# DYNAMIC_IMPORTS` in your entry file and every `.graphql` file found one level below `<cwd>/schema/` gets inlined at that marker:

```
schema/
  schema.graphql   # contains: # DYNAMIC_IMPORTS
  post/
    post.graphql
  user/
    user.graphql
```

## API

All symbols are re-exported from the package root (`@eol/gq`).

### `GraphQLHTTP(options)`

Returns a `(request) => Promise<Response>` handler. Pluggable into `Deno.serve`, [oak](https://jsr.io/@oak/oak), [hono](https://jsr.io/@hono/hono), or anything else Fetch-shaped.

Options:

| Option              | Type                                  | Description                                    |
| ------------------- | ------------------------------------- | ---------------------------------------------- |
| `schema`            | `GraphQLSchema`                       | Required. Executable schema.                   |
| `context`           | `(req) => Ctx \| Promise<Ctx>`        | Builds the resolver context per request.       |
| `graphiql`          | `boolean`                             | Serve GraphiQL on `GET` + `Accept: text/html`. |
| `headers`           | `HeadersInit`                         | Extra headers merged into every response.      |
| `playgroundOptions` | `Omit<RenderPageOptions, "endpoint">` | Passthrough options for the GraphiQL renderer. |

### `executeSchema(config)`

Re-export of `@graphql-tools/schema`’s `makeExecutableSchema`, renamed for brevity.

### `gql` *(tagged template)*

Parses a GraphQL string into a `DocumentNode`. Results are cached by normalized source, and embedded `DocumentNode` interpolations are inlined from their original source.

Companion knobs:

- `disableExperimentalFragmentVariables()`
- `disableFragmentWarnings()`
- `enableExperimentalFragmentVariables()`
- `resetCaches()`

### `importQL(path)`

Reads a `.graphql` file and resolves its imports. See [Loading schemas from `.graphql` files](#loading-schemas-from-graphql-files).

### `runHttpQuery(params, options, request)`

Low-level executor that `GraphQLHTTP` delegates to. Use it if you’re rolling your own transport but still want the context wiring.

### Types

`GQLOptions`, `GQLRequest`, `GraphQLParams`, `GraphQLHandler`, plus `RenderPageOptions` for the GraphiQL shell.

We also export commonly imported GraphQL types: `DocumentNode`, `ExecutionResult`, `GraphQLArgs`, `GraphQLFieldResolver`, `GraphQLResolveInfo`, `GraphQLScalarType`, `GraphQLSchema`, `GraphQLTypeResolver`, and `Source`.

## Features

- Import `*.graphql` files — explicit and dynamic — via `importQL`.
- Embedded GraphiQL via [`@eeeooolll/graphiql`](https://www.npmjs.com/package/@eeeooolll/graphiql) — Svelte 5, CodeMirror 6, served as a prebuilt IIFE bundle from jsDelivr.
- Ships typed; passes `deno check entry.ts` with no fuss.
- Zero build step — it’s Deno, you just import it.

## GraphiQL renderer options

`playgroundOptions` is forwarded to the HTML shell builder. All fields are optional:

| Field        | Type             | Description                                                              |
| ------------ | ---------------- | ------------------------------------------------------------------------ |
| `cdnUrl`     | `string`         | CDN base. Defaults to `//cdn.jsdelivr.net/npm`.                          |
| `faviconUrl` | `string \| null` | `null` skips the favicon; `undefined` uses the bundle's default.         |
| `title`      | `string`         | Document `<title>`. Defaults to `"GraphiQL"`.                            |
| `version`    | `string`         | Pin `@eeeooolll/graphiql` to a specific version on the CDN. Recommended. |

Pinning `version` is recommended — without it the shell hits jsDelivr's `@latest` cache, which can lag behind new releases by ~12h.

## License

MIT