dotql
v0.9.19
Published
graphql like but query by plain json. No more DSL or AST parsing
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.
