Tiny GraphQL client library. Compiles queries, fetches them and caches them, all in one tiny package.
const { gql, nanographql } = require('nanographql')
const Query = gql`
query($name: String!) {
movie (name: $name) {
releaseDate
}
}
`
const graphql = nanographql('/graphql')
const { errors, data } = graphql(Query({ name: 'Back to the Future' }))
Create a new graphql query function.
Create a new operation object that holds all data necessary to execute the query
against an endpoint. An operation can be stringified to a query (toString
),
serialized to a plain object (toJSON
) or iterated over.
Create a managed cache which fetches data as it is requested.
cache
: a custom cache store. Should implementget
andset
methods. The default is aMap
.fetch
: a customfetch
implementation. Thefetch
option should be a function which takes three arguments,url
,opts
and a callback function. The callback function should be called whenever there is an error or new data available. The default is an implementation ofwindow.fetch
.
Query the cache and fetch query if necessary. The options match that of
fetch
with a couple extra options. The callback will be called whenever
an error or new data becomes available.
The options are forwarded to the fetch
implementation but a few are
also used to determine when to use the cache and how to format the request.
cache
: The default behavior of nanographql mimics that offorce-cache
as it will always try and read from the cache unless specified otherwise. Any of the valuesno-store
,reload
,no-cache
,default
will cause nanographql to bypass the cache and call the fetch implementation. The valueno-store
will also prevent the response from being cached locally. See cache mode for more details.body
: If a body is defined, nanographql will make no changes to headers or the body itself. You'll have to append the operation to the body yourself.method
: If the operation is amutation
or if the stringified operation is too long to be transferred asGET
parameters, the method will be set toPOST
, unless specified otherwise.
key|key(variables[, cached])
: A unique identifier for the requested data. Can be a string or a function. Functions will be called with the variables and the cached data, if there is any. This can be used to determine the key of e.g. a mutation where the key is not known untill a response is retrieved. The default is the variables as a serialized string, or a stringified representation of the query if no variables are provided.parse(response[, cached])
: Parse the incoming data before comitting to the cache.mutate(cached)
: Mutate the cached data prior to reading from cache or fetching data. This is useful for e.g. immedately updating the UI while submitting changes to the back end.
One of the benefits of GraphQL is the strucuted format of the queries. When
passing a query to the gql
tag, nanographql will parse the string identifying
individual queries, mutations, subscritions and fragments and expose these as
individual operations. It will also mix in interpolated fragments from other
queries.
const choo = require('choo')
const html = require('choo/html')
const { gql, nanographql } = require('nanographql')
const { user } = gql`
fragment user on User {
id
name
}
`
const { GetUser, SaveUser } = gql`
query GetUser($id: ID!) {
user: getUser(id: $id) {
...${user}
}
}
mutation SaveUser($id: ID!, $name: String) {
user: saveUser(id: $id, name: $name) {
...${user}
}
}
`
const app = choo()
app.use(store)
app.route('/', main)
app.mount(document.body)
function store (state, emitter) {
const graphql = nanographql('/graphql')
state.api = (...args) => graphql(...args, render)
function render () {
emitter.emit('render')
}
}
function main (state, emit) {
const { api } = state
const { errors, data } = api(GetUser({ id: 'abc123' }), { key: 'abc123' })
if (errors) return html`<body><p>User not found</p><body>`
if (!data) return html`<body><p>Loading</p><body>`
return html`
<body>
<form onsubmit=${onsubmit}>
Name: <input value="${data.user.name}" name="username">
<button>Save</button>
</form>
</body>
`
function onsubmit (event) {
api(SaveUser({ id: 'abc123', name: this.username.value }), {
key: 'abc123',
mutate (cached) {
const user = { ...cached.data.user, name }
return { data: { user } }
}
})
event.preventDefault()
}
}