@jsonql/client

jsonql js http and socket client for browser with multiple API for different framework

Usage no npm install needed!

<script type="module">
  import jsonqlClient from 'https://cdn.skypack.dev/@jsonql/client';
</script>

README

@jsonql/client

This is jsonql browser client comes with jsonql-client (http) and optional socket clients, plus various modules for ui frameworks

Basic Example

Stock http client

import jsonqlClient from '@jsonql/client'
import Fly from 'flyio'
const config = {} // your configuration options

jsonqlClient(config)
  .then(client => {
    // start to do your thing
  })

Using the static client with pre-generated contract (works better with Third party JS frameworks)

import { jsonqlStaticClient } from '@jsonql/client/static'
import contract from 'path/to/your/public-contract.json'
import Fly from 'flyio' // or specific client to your need

const client = jsonqlStaticClient(Fly, { contract })

client.query.helloWorld()
  .then(msg => {
    // you get Hello world!
  })

Third party JS Framework modules

We have developed several modules to integrate with some of the third party JS frameworks.

Vuex module

Vuex store support was add in version 1.5.19

First create a new Vuex store file (let say call it jsonql.js)

import contract from 'path/to/your/public-contract.json'
import { jsonqlVuex } from '@jsonql/client/vue'
import Fly from 'flyio'

const jsonqlVuexModule = jsonqlVuex(Fly, { contract })

export { jsonqlVuexModule }

Now in your store.js where you define your Vuex store

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

import { jsonqlVuexModule } from './jsonql'

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  getters: {},
  modules: {
    jsonqlVuexModule
  }
})

This Vuex module is namespaced. In your component

<template>
  <div>
    {{hello}}
  </div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  name: 'test',
  computed: {
    hello() {
      return this.getJsonqlResult('helloWorld')
    }
  }
  actions: {
    ...mapActions('jsonqlVuexModule', ['helloWorld'])
  },
  getters: {
    ...mapGetters('jsonqlVuexModule', ['getJsonqlResult'])
  }
}
</script>

Prefix your resolver with their type

There is a little different between our core jsonql client and in the above module. Normally, the client will namespaced each methods under their type:

jsonql()
  .then(client => {
    // query
    client.query.helloWorld()
    // mutation
    client.mutation.updateSomething()
    // auth
    client.auth.login()
    // etc
  })

We try to be compatible with the Vuex (or most of the js state machine) style, we remove the namespace, and just construct the resolver under the client, there is one little potential danger, when you don't name each of your resolver with a unique name. But again this is an edge case, I don't think anyone in their right mind will have a query.login, auth.login at the same time?

But when you find yourself in this situation. You can use the prefix option.

import contract from 'path/to/your/public-contract.json'
import { jsonqlVuex } from '@jsonql/client/vue'
import Fly from 'flyio'
// here we pass the prefix: true option
const jsonqlVuexModule = jsonqlVuex(Fly, { contract, prefix: true })

export { jsonqlVuexModule }

Then it will turn query.helloWorld into queryHelloWorld.

<template>
  <div>
    {{hello}}
  </div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  name: 'test',
  computed: {
    ...mapGetters('jsonqlVuexModule', ['getJsonqlResult']),
    hello() {
      return this.getJsonqlResult('queryHelloWorld')
    }
  },
  actions: {
    ...mapActions('jsonqlVuexModule', ['queryHelloWorld'])
  }
}
</script>

If you need this option, then remember, everything will prefix with their resolver type name, in camel case.

Vuex getter: getJsonqlResult

You should notice there is a Vuex getter method call getJsonqlResult, and you pass the resolver name (with prefix if you use prefix:true option). Then you will get back the last resolver call result via this getter.

The reason is in the Vuex model, after the call to resolver, we store (commit) the result in our internal result state, and key with the resolver name. And whenever a new result return, it will get overwritten, because it's a flat object.

Of course, you can simply call the actions, and wait for the promise to resolve. You will get the same effect. For example:

<template>
  <div>
    {{hello}}
  </div>
</template>
<script>
// do your import vuex etc
export default {
  data() {
    hello: 'waiting ...'
  }
  created() {
    this.helloWorld()
      .then(result => {
        this.hello = result
      })
  },
  methods() {
    ...mapActions('jsonqlVuexModule', ['helloWorld'])
  }
}

</script>

Vuex getter: getJsonqlError

Whenever an error happens, we do the same like success result, we commit to our internal error state, and you can use this getter to get it. And after we commit, we will throw it again which wrap in a generic Error. So you can also catch it again. For example:

<template>
  <div>
    <p>{{hello}}</p>
    <span class="error">{{error}}</span>
  </div>
</template>
<script>
// do your import vuex etc
export default {
  data() {
    hello: 'waiting ...'
  }
  created() {
    this.helloWorld()
      .then(result => {
        this.hello = result
      })
  },
  computed: {
    ...mapGetters('jsonqlVuexModule', ['getJsonqlError']),
    error() {
      return this.getJsonqlError('helloWorld')
    }
  }
  methods() {
    ...mapActions('jsonqlVuexModule', ['helloWorld'])
  }
}
</script>

This getter is literally identical to getJsonqlResult.


https://jsonql.org

NEWBRAN LTD UK & T01SOURCE CN