Use it with anything
Pair typograph with graphql-request, fetch, or any GraphQL client of your choice.
Typograph's core client is intentionally tiny. It only does two things:
- Turns your selection set into a GraphQL string (
res.toGraphQL()). - Hands you the variables object you'd send with it (
res.variables).
That means it works with any transport that takes a GraphQL string. You don't need an adapter, a plugin, or a special client — typograph just produces the same things you'd write by hand, and you plug them into whatever you already use.
The trick that ties it all together is typeof res.returnType — a
phantom type that gives you the inferred response shape for free.
Hand it to whichever client you're using and you get a fully-typed
result back.
Setup
You only need the core client and your schema:
import { createClient } from "@overstacked/typograph";
import { typeDefs } from "./schema";
const client = createClient(typeDefs);Build the operation once:
const res = client.query(
{ getPost: { id: true, title: true } },
{ variables: { id: "p1" } },
);res.toGraphQL(), res.variables, and typeof res.returnType are
the three things every example below uses.
Apollo Client
Typograph ships a first-party Apollo integration — see
Apollo Client for typed useQuery / useMutation /
useSubscription hooks. If you'd rather wire it up yourself:
import { gql, useQuery } from "@apollo/client";
const { data } = useQuery<typeof res.returnType>(gql(res.toGraphQL()), {
variables: res.variables,
});
data?.getPost.title;
// ^? stringgraphql-request
import { request } from "graphql-request";
const data = await request<typeof res.returnType>(
"/graphql",
res.toGraphQL(),
res.variables,
);
data.getPost.title;
// ^? stringReact Query
Typograph ships a first-party React Query integration — see
React Query for typed useQuery / useMutation
hooks. If you'd rather wire it up yourself, the pattern is:
import { useQuery } from "@tanstack/react-query";
import { request } from "graphql-request";
const { data } = useQuery({
queryKey: ["getPost", res.variables],
queryFn: () =>
request<typeof res.returnType>(
"/graphql",
res.toGraphQL(),
res.variables,
),
});Plain fetch
If you don't want a GraphQL client at all, fetch is enough:
const response = await fetch("/graphql", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
query: res.toGraphQL(),
variables: res.variables,
}),
});
const { data } = (await response.json()) as {
data: typeof res.returnType;
};
data.getPost.title;
// ^? stringurql (without the integration)
If you'd rather use urql directly than the first-party integration, the same pattern works:
import { Client } from "urql";
const urql = new Client({ url: "/graphql" });
const result = await urql
.query<typeof res.returnType>(res.toGraphQL(), res.variables)
.toPromise();
result.data?.getPost.title;
// ^? stringThe point
In every example above, the only thing that changes is the transport. The schema, the selection set, and the inferred response type are exactly the same. You can swap clients freely — typograph isn't tied to any of them.