lightning-graphql
v3.1.0
Published
Lite Cache-less GraphQL client with excellent type-support for Node and Browsers.
Downloads
2
Maintainers
Readme
Lightning GraphQL
Lite Cache-less GraphQL client with excellent type-support for Node and Browsers. This library's default datafetcher only works with queries and mutations and not subscriptions, so if you want that still use the fetcher option and provide your own datafetcher (providing your own datafetcher can also fix other things e.g. the queries being cache-less)
Why?: I couldn't find a simple way to go from writing graphql queries on my server that wouldn't be cached between requests, and I also wanted a library that didn't compromise on type-safety and great developer experience (DX).
Table Of Contents
External Code Demos:
Stackblitz Collection of Demos
Client Examples
Given a queries.graphql like so that has been generated to a file called ./__generated__/client-types.ts
:
query Books {
books {
title
author
}
}
query Authors {
authors
}
query BookByTitle($title: String!) {
findBookByTitle(title: $title) {
title
author
}
}
mutation Noop {
noop
}
We can write our client like so:
client.ts
import {GraphQLClient} from "lightning-graphql"
// Generated from graphql-codegen with TypedDocumentNodes.
import * as source from "./__generated__/client-types";
const client = GraphQLClient({
source,
endpoint: serverURL,
});
// All these methods are camelcased named versions of queries and mutations written in the above queries file.
// The methods below also come with great type-hints and safety.
const book = await client.bookByTitle({
title: "The Great Gatsby",
}); // get Book by title
const books = await client.books({}); // get all Books
const truthy = await client.noop({}); // runs the Noop mutation
const authors = await client.authors({}); // get all Authors
If you notice above our client is generated and populated with all information from the Query file. This is possible because of GraphQL Codegen's TypedDocumentNodes.
Minimal Example with Server and Full Type Support
Server Setup
First we get our ./src/schema.graphql file:
type Book {
title: String
author: String
}
type Query {
books: [Book]
authors: [String]
findBookByTitle(title: String!): Book
}
type Mutation {
noop: Boolean!
}
Then we write a somewhat large ./src/server.js file:
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { readFileSync } from "node:fs";
import { ListenOptions } from "node:net";
import { join } from "node:path";
const books = [
{
title: "The Great Gatsby",
author: "F. Scott Fitzgerald",
},
{
title: "Where the Sidewalk Ends",
author: "Shel Silverstein",
},
];
const typeDefs = readFileSync(join(__dirname, "schema.graphql"), {
encoding: "utf-8",
});
export const resolvers = {
Query: {
books: () => books,
authors: () => books.map((x) => x.author),
findBookByTitle(_root: any, { title }: { title: string }) {
return books.find((x) => x.title === title);
},
},
Mutation: {
noop: () => true,
},
};
const server = (listen: ListenOptions) => {
const server = new ApolloServer({
typeDefs,
resolvers,
});
return {
async listen() {
return startStandaloneServer(server, {
listen,
});
},
async unlisten() {
await server.stop();
},
};
};
const port = 3322;
server({
port: 3322
}).listen();
Client Setup
With the server finished we then write our query in ./src/queries.graphql
query Books {
books {
title
author
}
}
query Authors {
authors
}
query BookByTitle($title: String!) {
findBookByTitle(title: $title) {
title
author
}
}
mutation Noop {
noop
}
Then we generate types for the Schema and Query:
By first installing packages for codegen:
Choose an npm or yarn install:
npm
npm i -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node
yarn:
yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node
Then setting up the following ./codegen.yml:
# You provide a schema and documents
schema: "./src/schema.graphql"
documents: "./src/queries.graphql"
generates:
# These line can change to where you want the types to go.
./src/__generated__/client-types.ts:
# All three of these are required
plugins:
- "typescript"
- "typescript-operations"
- "typed-document-node"
The following package.json script called generate
:
{
// ...
"scripts": {
// ...
"generate": "graphql-codegen --config codegen.yml"
}
// ...
}
Then generate the client types with:
npm run generate
Then we can finally write our Queries in a ./src/client.ts file where we get all the type-safe goodness!
import {GraphQLClient} from "lightning-graphql";
const serverURL = "http://localhost:3322/graphql";
const client = GraphQLClient({
source: await import("./__generated__/client-types"),
endpoint: serverURL,
});
// All these methods are camelcased named versions of queries and mutations written in the above queries file.
const book = await client.bookByTitle({
title: "The Great Gatsby",
}); // get Book by title
const books = await client.books({}); // get all Books
const truthy = await client.noop({}); // runs the Noop mutation
const authors = await client.authors({}); // get all Authors
Supplying your own custom fetcher instead of using the default fetch.
import {GraphQLClient} from "lightning-graphql"
const client = GraphQLClient({
source: await import("./__generated__/client-types"),
endpoint: serverURL,
fetcher ({endpoint, query, type}) {
return async (variables, options) => {
// Go Fetch Your Data!
}
}
});
Supplying fetchOptions.
There are two ways to supply fetchOptions:
import {GraphQLClient} from "lightning-graphql"
// First way is to send it into the GraphQLClient
const client = GraphQLClient({
source: await import("./__generated__/client-types"),
endpoint: serverURL,
options: {
// Send in a context if you have a custom fetcher.
context: {},
fetchOptions: {
// extra fetch options any options given to fetch's second parameter work here.
}
}
});
// First way is to send it into the GraphQLClient
const books = await client.books({}, {
// Send in a context.
context: {},
fetchOptions: {
// Extra fetch options.
}
})