dotql
v0.9.19
Published
graphql like but query by plain json. No more DSL or AST parsing
Downloads
5
Maintainers
Readme
dotql
graphql like but query by plain json. No more DSL or AST parsing
A graphql like client and server without graphql DSL, faster parsing.
Built-in implementation for live-query (by ping or/and push)
List of features
- strictly follow graphql but in json, no more DSL parsing
- small in size, all-in-one instead of few heavy weighted packages
- built-in implementation for live-query (by ping or/and push)
Basic Usage
dotql query
client.query({
getUserById: {
// with id:'user_01' arguments
$args: { id: 'user_01' },
// ask for name and photo fields
name: 1,
photo: 1,
},
})
instead of graphql query
graphqlClient.query(gql`
{
getUserById(id: "user_01") {
name
photo
}
}
`)
mutate and watch server data via client
const client = new Client({
callServer: specs => server.query(specs),
})
// watch
const unwatch = client.watch({ getUserById: { $args: 'user_01', id: 1, count: 1 } }, (data, error) => {
watchData = data
})
await delay()
// watch will fill initial data
expect(watchData).toMatchObject({ getUserById: { $type: 'User', id: 'user_01', count: undefined } })
// mutate
await client.mutate({ setUserById: { $args: { id: 'user_01', count: 10 } } })
await delay()
expect(watchData).toMatchObject({ getUserById: { $type: 'User', id: 'user_01', count: 10 } })
use prepared queries for smaller request payload and hiding schema detail
// use prepared query 'getUserById_1'
expect(await client.query({ $query: 'getUserById_1', where: 'user_01' })).toMatchObject({
getUserById: { $type: 'User', id: 'user_01' },
})
// use prepared mutation 'setUserById_1'
await client.mutate({ $mutation: 'setUserById_1', userId: 'user_01', count: 20 })
await delay()
expect(watchData).toMatchObject({ getUserById: { $type: 'User', id: 'user_01', count: 20 } })
create server instance
const server = new Server({
schema: {
Queries: {
getUserById: {
type: 'User',
resolve: async (dot, args, context, info) => {
return { ...userDb[args], id: args }
},
},
},
Mutations: {
setUserById: {
type: 'User',
resolve: async (dot, args, context, info) => {
return (userDb[args.id] = Object.assign(userDb[args.id] || {}, args))
},
},
},
User: {
id: { type: 'String' },
count: { type: 'Int' },
blogs: {
type: ['Object'],
resolve: async (dot, args, context, info) => {
// batch.load() will auto create new DataLoader(batchLoader)
const blogId = await context.batch.load(dot.id)
return [{ blogId }]
},
batchLoader: async keys => _.map(keys, k => `< ${k} >`),
},
},
},
prepared: {
Queries: {
// prepared query with name='getUserById_1'
getUserById_1: {
// { $ref: 'where' } will be replace by prepared query references
getUserById: { $args: { $ref: 'where' }, id: 1, count: 1 },
},
},
Mutations: {
setUserById_1: {
// $refs will pick multiple variables
setUserById: { $args: { $refs: { id: 'userId', count: 'count' } } },
},
},
},
})
trigger resolve to call context.batch.load() which use built-in support of dataloader
// resolve via batchLoader
result = await client.query({ getUserById: { $args: 'user_01', blogs: 1 } })
expect(result).toMatchObject({ getUserById: { $type: 'User', blogs: [{ blogId: '< user_01 >' }] } })
TODO
Docs
- eTags and channels
- useMutate(func, deps)
Size
dotql client and server
graphql (not yet include apollo or relay)
Contributing
Keep it simple. Keep it minimal. Don't put every single feature just because you can.