Spec Compliant
Graffle complies with the GraphQL over HTTP and GraphQL Multipart Request specifications.
Minimal. Extensible. Type Safe. Runs everywhere.

Sponsors ❤️
Pre-Release Software
Graffle is still in development. Install with npm install graffle@next graphql to use the latest pre-release version.
import { Graffle } from 'graffle' const graffle = Graffle .create() .transport({ url: 'https://countries.trevorblades.com/graphql' }) const data = await graffle.gql` query { countries(filter: { name: { in: ["Canada", "Germany", "Japan"] } }) { name capital emoji } } `.send() console.log(data) // ^?Optional generated TypeScript API for building type-safe queries. Get full IntelliSense and static type safety with a native TypeScript interface instead of GraphQL strings.
const pokemons = await graffle.query.pokemons({ $: { filter: { name: { in: ['Pikachu', 'Charizard'] } } }, name: true, hp: true, })Use standard GraphQL syntax with full type inference. Write queries as strings and get complete type safety for variables and results without any code generation.
const data = await graffle.gql(` query pokemonByName($name: String!) { pokemonByName(name: $name) { name hp } } `).pokemonByName({ name: 'Pikachu' })Compose middleware to add observability, file uploads, schema errors, and more. Build your own extensions with a clean, type-safe API.
const graffle = Graffle .create() .use(OpenTelemetry()) .use(SchemaErrors) const data = await graffle.query.pokemons({ name: true })Register codecs for custom scalars and Graffle automatically encodes arguments and decodes results. Works seamlessly with dates, big integers, or any custom type.
const graffle = Graffle.create().scalar('Date', { decode: (value: string) => new Date(value), encode: (value: Date) => value.toISOString(), }) const pokemons = await graffle.query.pokemons({ $: { filter: { birthday: { lte: new Date('1987-01-13') } } }, birthday: true, // JavaScript Date })