jsonql-contract
v1.9.2
Published
JS API / command line tool to generate the contract.json for jsonql
Downloads
115
Readme
jsonql-contract
an automated tool to generate the contract file using AST / JSDOC
The contract file is the heart of the entire jsonql libraries.
This is how we bind everything together. And jsonql-contract
is the core engine to generate this files.
Installation
$ npm install jsonql-contract --global
You don't normally need to execute this directly. This module is included in every jsonql libraries tool that require it, and it's run automatically. But for testing purpose, you should install it and get yourself familiar with the contract files.
Command line options
Type jsonql-contract --help
will show you all the available commands and options.
Here are all the command line options:
Local development
$ jsonql-contract create /path/to/your/resolvers
by default a contract.json
file will be generate in the same directory where you run this command.
$ jsonql-contract create /path/to/your/resolvers /path/to/your/contracts
This will put the contract.json
into /path/to/your/contracts
.
If you are create a static version for your js client for distribution
$ jsonql-contract create /path/to/our/resolvers /path/to/your/contract --public=1
This will generate the public version of jsonql contract name public-contract.json
.
Using config
flag to import a configuation file
You can use a json or js file to specify all the options:
{
"inDir": "/path/to/resolvers",
"outDir": "/path/to/contract",
"enableAuth": true
}
Then you can:
$ jsonql-contract config ./config.json
Supported JS
We only support common js (cjs
) style function exports and ES6 import / export style (you need to pass the jsType: ES
when you pass configuration options to the contract generator api)
/**
* This is a query and we REQUIRED to write correct jsdoc since v1.2.x
* @param {number} param1
* @param {number} param2
* @param {number} [param3=100] optional with default value of 100
* @return {number} sum of all
*/
module.exports = function someResolver(param1, params2, param3=100) {
return param1 + param2 + param3;
}
ES6 style:
/**
* This is a query and we REQUIRED to write correct jsdoc since v1.2.x
* @param {number} param1
* @param {number} param2
* @param {number} [param3=100] optional with default value of 100
* @return {number} sum of all
*/
export default function someResolver(param1, param2, param3 = 100) {
return param1 + param2 + param3
}
Resolvers folder structure
As of the jqonql-koa alpha.7 release. It will only support the following folder structure
/resolvers/
/query/name-of-function.js
/another-function/
/index.js
/mutation/name-of-update.js
/another-name-of-function/
/index.js
Inside the resolver:
/**
* we REQUIRED to write correct jsdoc from v1.2.x
* @param {string} name
* @param {number} pos
* @param {object} [options={}]
* @return {object} combination
*/
module.exports = async function(name, pos, options = {}) {
// do your things
return result;
}
Its recommended to use an async
method as your resolver. Inside, you can return promise or use async
await
.
Because when we execute your code it will look (not exactly the same) the following:
ctx.body = await processResult(opts);
For mutation, there will only be 2 parameters payload
and condition
/**
* This is the signature of a mutation function
* @param {object} payload
* @param {object} condition
* @return {boolean} true on success
*/
module.exports = function(payload, condition) {
// do your thing
}
To properly documented your mutation code for the client side validation, you should do the following comment:
/**
* This is the signature of a mutation function
* @param {object} payload
* @param {string} payload.name key name
* @param {object} condition
* @param {number} condition.id to id the field
* @return {boolean} true on success
*/
module.exports = function({ name }, { id }) {
// do something with your data
}
Once the contract finish parsing the code, the contract result will look like this:
{
"mutation": {
"someFunction": {
"params": [
{
"type": "object",
"name": "payload",
"keys": [
{
"type": "string",
"name": "name",
"parent": "payload"
}
]
},
{
"type": "object",
"name": "condition",
"keys": [
{
"type": "number",
"name": "id",
"parent": "condition"
}
]
}
]
}
}
}
The above show you how the client will take the parameter, the children will fold under
the keys
property. And the client side validation will able to correctly validate your
input before send to the server.
Also using jsdoc to id the type of your parameters solve the default value problem, and the client library will able to correctly apply the default value when call.
The result contract
There will be type information for the parameter, they will all set to mixed
type by default.
We have to wait until the flow interface completed before we can lock down on the type.
Another solution is enforcing writing standard compliant comment, and allow us to understand what's your parameters expected value type. Writing good comment is really a standard practice for any programmer.
1.2.X with jsdoc-api
Since we are not using any type system (if you want to, we have the Typescript port in future)
Therefore, if we need to enable the validation feature on the client; you MUST write proper jsdoc.
We will take the jsdoc output and create an additional temporary contract file (contract-jsdoc.json) and the base public contract will be the combination of two files. We also allow to create another contract file based on the NODE_ENV
so let say, if you are currently under
NODE_ENV=development
then we will look for a development.json
and use the property to overload the base contract file (But this is
rarely necessary, and this feature might remove in the future release).
TODOS
- Update README about the
public
folder within each resolvers - ~~Add watch mode during development~~ - this is not activate until the other part is ready
- ~~Add accept config file for easier to run in command line~~
- add
Auth
part - add
Socket
part - add
File
part (not in the code base yet)
MIT (c) to1source & NEWBRAN LTD