diff --git a/packages/errors/src/final-catch.js b/packages/errors/src/final-catch.js index a6b7001b396279738b1c79f890df519b117acb4b..b6908f10e39a00d6369addb5a84c708f9217e74a 100644 --- a/packages/errors/src/final-catch.js +++ b/packages/errors/src/final-catch.js @@ -36,28 +36,28 @@ export default function finalCatch(e) { const detail = e.detail || e; switch (true) { case e instanceof Jsonql406Error: - throw new Jsonql406Error(msg, detail); + throw new Jsonql406Error(msg, detail) case e instanceof Jsonql500Error: - throw new Jsonql500Error(msg, detail); + throw new Jsonql500Error(msg, detail) case e instanceof JsonqlAuthorisationError: - throw new JsonqlAuthorisationError(msg, detail); + throw new JsonqlAuthorisationError(msg, detail) case e instanceof JsonqlContractAuthError: - throw new JsonqlContractAuthError(msg, detail); + throw new JsonqlContractAuthError(msg, detail) case e instanceof JsonqlResolverAppError: - throw new JsonqlResolverAppError(msg, detail); + throw new JsonqlResolverAppError(msg, detail) case e instanceof JsonqlResolverNotFoundError: - throw new JsonqlResolverNotFoundError(msg, detail); + throw new JsonqlResolverNotFoundError(msg, detail) case e instanceof JsonqlEnumError: - throw new JsonqlEnumError(msg, detail); + throw new JsonqlEnumError(msg, detail) case e instanceof JsonqlTypeError: - throw new JsonqlTypeError(msg, detail); + throw new JsonqlTypeError(msg, detail) case e instanceof JsonqlCheckerError: - throw new JsonqlCheckerError(msg, detail); + throw new JsonqlCheckerError(msg, detail) case e instanceof JsonqlValidationError: - throw new JsonqlValidationError(msg, detail); + throw new JsonqlValidationError(msg, detail) case e instanceof JsonqlServerError: - throw new JsonqlServerError(msg, detail); + throw new JsonqlServerError(msg, detail) default: - throw new JsonqlError(msg, detail); + throw new JsonqlError(msg, detail) } } diff --git a/packages/koa/index.js b/packages/koa/index.js index a02666e619e59ee28a26b225657006789e7615d3..eb25d4da76b42e5960489d0737a6b5e20a5d4e3b 100755 --- a/packages/koa/index.js +++ b/packages/koa/index.js @@ -17,17 +17,17 @@ const { errorsHandlerMiddleware, initMiddleware } = require('./src') -const { getDebug, setter, getter } = require('./src/lib') +const { getDebug } = require('./src/lib') const debug = getDebug('main') // main module.exports = function(config = {}) { // first check the config const opts = configCheck(config) - + debug('[jsonql-koa] init opts', opts) // export let middlewares = [ - initMiddleware(opts, setter, getter), + initMiddleware(opts), helloMiddleware(opts), contractMiddleware(opts) ] diff --git a/packages/koa/package.json b/packages/koa/package.json index a6f9302e97f67629fa1623ca3a3454a177154405..3328b2c59800f7f0536801737164eb1e817aba2c 100755 --- a/packages/koa/package.json +++ b/packages/koa/package.json @@ -46,14 +46,13 @@ "jsonql-contract": "^1.7.7", "jsonql-errors": "^1.1.2", "jsonql-jwt": "^1.2.5", - "jsonql-node-client": "^1.1.5", + "jsonql-node-client": "^1.1.6", "jsonql-params-validator": "^1.4.4", - "jsonql-resolver": "^0.6.2", + "jsonql-resolver": "^0.6.5", "jsonql-web-console": "^0.4.3", "koa": "^2.8.1", "koa-compose": "^4.1.0", - "lodash": "^4.17.15", - "node-cache": "^4.2.1" + "lodash": "^4.17.15" }, "author": "to1source ", "contributors": [ diff --git a/packages/koa/src/contract-middleware.js b/packages/koa/src/contract-middleware.js index 605405a45ff31e3649fd87ccfe48db4df1187aaa..6bdade1088d40e73e7289f791121c2e3dcbc451e 100755 --- a/packages/koa/src/contract-middleware.js +++ b/packages/koa/src/contract-middleware.js @@ -55,7 +55,7 @@ const handleContract = (opts, ctx, contract) => { // @1.3.2 add a filter here to exclude the description field // just to reduce the size, but we serve it up if this is request with // desc=1 param - useful for the jsonql-web-console - debug('handleContract', ctx.query.desc) + // debug('handleContract', ctx.query.desc) const key = Object.keys(SHOW_CONTRACT_DESC_PARAM)[0] let desc = !!(ctx.query[key] && ctx.query[key] === SHOW_CONTRACT_DESC_PARAM[key]) handleOutput(opts)(ctx, packResult( @@ -124,6 +124,7 @@ module.exports = function(opts) { if (contractAuth(ctx, opts)) { let publicContractJson = ctx.state.jsonql.publicContract; if (!publicContractJson) { + debug(`call the get public contract here`, opts.name) // This should be a one off event publicContractJson = await getContract(opts, true) ctx.state.jsonql.publicContract = publicContractJson; diff --git a/packages/koa/src/core-middleware.js b/packages/koa/src/core-middleware.js index 69541d2273e21e779a83a9cb80910b2921beb401..234e748867287030013b54a6b429cbf8fe322e89 100755 --- a/packages/koa/src/core-middleware.js +++ b/packages/koa/src/core-middleware.js @@ -15,6 +15,9 @@ module.exports = function(opts) { const { contract, resolverType } = ctx.state.jsonql; debug('isJsonqlRequest', resolverType) if (resolverType === QUERY_NAME || resolverType === MUTATION_NAME) { + // debug(`Is jsonql query`, contract, opts) + // The problem is - the config is correct + // but the contract return the previous one return resolveMethod(ctx, resolverType, opts, contract) } } else { diff --git a/packages/koa/src/init-middleware.js b/packages/koa/src/init-middleware.js index e00351539b87bed6875fb22e4449d3395bba5ad7..afa9e887b50f098b953b92bacae135d006f186b9 100644 --- a/packages/koa/src/init-middleware.js +++ b/packages/koa/src/init-middleware.js @@ -79,12 +79,12 @@ const isJsonpCall = function(ctx) { * @param {function} getter nodeCache get * @return {function} middleware */ -module.exports = function(opts, setter, getter) { +module.exports = function(opts) { // export return async function(ctx, next) { ctx.state.jsonql = {}; - ctx.state.jsonql.setter = setter; - ctx.state.jsonql.getter = getter; + // ctx.state.jsonql.setter = setter; + // ctx.state.jsonql.getter = getter; // first check if its calling the jsonql api const isJsonql = isJsonqlRequest(ctx, opts) // init our own context diff --git a/packages/koa/src/lib/config-check/index.js b/packages/koa/src/lib/config-check/index.js index e911bcf498890b2eeab02b5f7d60f26e39464d4f..506ddeced7c90819ab15bdaea6eed55071ad795e 100644 --- a/packages/koa/src/lib/config-check/index.js +++ b/packages/koa/src/lib/config-check/index.js @@ -1,6 +1,7 @@ // wrap all the options and method in one instead of all over the places const { join, resolve } = require('path') const fsx = require('fs-extra') +const _ = require('lodash') const { checkConfig, isString } = require('jsonql-params-validator') const { rsaPemKeys } = require('jsonql-jwt') @@ -11,31 +12,38 @@ const debug = getDebug('config-check') /** * break out from the applyAuthOptions because it's not suppose to be there + * @NOTE v1.3.8 change it to a fully functional interface * @param {object} config configuration * @return {object} with additional properties */ const applyGetContract = function(config) { - const { contract } = config; - if (isContractJson(contract)) { - config.contract = contract; - // @ 1.3.4 - also generate the public contract - if (config.withPublicContract) { - debug(`get cache public contract`) - getContract(config, true) - } - } else { - // this will pass a Promise then resolve inside the middleware - config.initContract = getContract(config) - .then(contract => { - // @ 1.3.4 - if (config.withPublicContract) { - debug(`get new public contract`) - getContract(config, true) - } - return contract; - }) - } - return config; + return _(config) + .chain() + .thru(config => { + const { contract } = config; + if (isContractJson(contract)) { + config.contract = contract; + return [true, config] + } + return [false, config] + }) + .thru(result => { + let [processed, config] = result + if (!processed) { + debug(`call initContract`) + // get resolve later inside the middleware + config.initContract = getContract(config) + } + return config; + }) + .thru(config => { + if (config.withPublicContract) { + debug(`call generate public contract`) + getContract(config, true) + } + return config; + }) + .value() } /** diff --git a/packages/koa/src/lib/config-check/options.js b/packages/koa/src/lib/config-check/options.js index d666dda4f066271d3cb07d83029178e2573d1023..987cae0641898c99e05eaef9d286465de376c058 100755 --- a/packages/koa/src/lib/config-check/options.js +++ b/packages/koa/src/lib/config-check/options.js @@ -49,6 +49,7 @@ const constProps = { }; const appProps = { + name: createConfig('jsonql-koa', [STRING_TYPE]), // this is for ID which one is which when use as ms expired: createConfig(0, [NUMBER_TYPE]), // allow user to change their auth type methods name loginHandlerName: createConfig(ISSUER_NAME, [STRING_TYPE]), diff --git a/packages/koa/src/lib/contract-generator/index.js b/packages/koa/src/lib/contract-generator/index.js index cc53e5d2835d7eebf1187a7c7a2df5fc22ada8cc..2e334287e8df84e3233d9d993fe40b43901fa2e3 100644 --- a/packages/koa/src/lib/contract-generator/index.js +++ b/packages/koa/src/lib/contract-generator/index.js @@ -15,7 +15,7 @@ module.exports = function(config, pub = false) { const ps = fork(join(__dirname, 'run.js')) const key = pub ? 'public' : 'private'; if (contractCache[key]) { - debug(`return ${key} contract from cache`) + debug(`return ${key} contract from cache`, contractCache[key]) // this is the problem - if we want to keep it consistent then // we should always provide the contract key --> cache is optional! // { contract: contractCache[key], cache: true } @@ -26,7 +26,7 @@ module.exports = function(config, pub = false) { return new Promise((resolver, rejecter) => { ps.on('message', msg => { if (msg.contract) { - contractCache[key] = msg.contract; + // contractCache[key] = msg.contract; // <-- disable cache // return return resolver(msg.contract) } diff --git a/packages/koa/src/lib/contract-generator/process-contract.js b/packages/koa/src/lib/contract-generator/process-contract.js index 63902d10653ee8388c63df0276d8ab86fd293469..9a6a4a4eba0279510c8b5426e8c65a3cd6bed59c 100644 --- a/packages/koa/src/lib/contract-generator/process-contract.js +++ b/packages/koa/src/lib/contract-generator/process-contract.js @@ -1,7 +1,7 @@ // wrap the method in the init-middleware here -const { isContractJson } = require('../utils') const { JsonqlError } = require('jsonql-errors') -const debug = require('debug')('jsonql-koa:process-contract') +const { isContractJson, getDebug } = require('../utils') +const debug = getDebug('process-contract') /** * Create the start of chain @@ -20,16 +20,17 @@ const getFromOpts = opts => { * @return {object} promise to resolve the contract */ module.exports = async function processContract(ctx, opts) { - const { setter, getter } = ctx.state.jsonql; + // const { setter, getter } = ctx.state.jsonql; return getFromOpts(opts) .then(c => c || false) - .then(c => !c ? getter('contract') : c) + // .then(c => !c ? getter('contract') : c) .then(c => { if (!c) { if (!ctx.state.jsonql.contract && opts.initContract && opts.initContract.then) { debug('calling the initContract to get the contract') return opts.initContract.then(c => { - setter('contract', c) + // disable the cache for the time being + // setter('contract', c) return c; }) } diff --git a/packages/koa/src/lib/index.js b/packages/koa/src/lib/index.js index 3fdbf579a5a4a6e67c24292541a34e5d68b1211a..0b75fff0deed743878535bdca72c39058a8da9d2 100755 --- a/packages/koa/src/lib/index.js +++ b/packages/koa/src/lib/index.js @@ -32,7 +32,7 @@ const { const getContract = require('./contract-generator') const processJwtKeys = require('./config-check/process-jwt-keys') -const { setter, getter } = require('./cache') + const { createTokenValidator } = require('jsonql-jwt') // update on v1.3.7 const { resolveMethod } = require('jsonql-resolver') @@ -69,8 +69,5 @@ module.exports = { processJwtKeys, - setter, - getter, - createTokenValidator } diff --git a/packages/koa/src/lib/utils.js b/packages/koa/src/lib/utils.js index 8b913d5b7246e07049ac45e42d8127b773b6eed7..37b1331877e1c1b9eca6071a532b51df6257c95c 100755 --- a/packages/koa/src/lib/utils.js +++ b/packages/koa/src/lib/utils.js @@ -1,10 +1,10 @@ // util methods -const _ = require('lodash'); -const { join } = require('path'); -const fs = require('fs'); -const { inspect } = require('util'); -const { isObject } = require('jsonql-params-validator'); -const jsonqlErrors = require('jsonql-errors'); +const _ = require('lodash') +const { join } = require('path') +const fs = require('fs') +const { inspect } = require('util') +const { isObject } = require('jsonql-params-validator') +const jsonqlErrors = require('jsonql-errors') const { JsonqlResolverNotFoundError, getErrorByStatus, diff --git a/packages/koa/tests/fixtures/resolvers/mutation/update-ms-service.js b/packages/koa/tests/fixtures/resolvers/mutation/update-ms-service.js index d93ef8fce75dff70d4c8dba6e43f6d240b0ce58c..62b1752475351de1e838f97b3dba1b76c0eb8b1e 100644 --- a/packages/koa/tests/fixtures/resolvers/mutation/update-ms-service.js +++ b/packages/koa/tests/fixtures/resolvers/mutation/update-ms-service.js @@ -5,10 +5,9 @@ const debug = require('debug')('jsonql-koa:mutation:update-ms-service') * @return {string} msg return from nodeClient */ module.exports = async function updateMsService(payload) { + const client = await updateMsService.client() - debug('payload', payload) + debug(client) - const client = await updateMsService.clients('nodeClient0') - - return client.query.msService(payload) + return client.query.subMsService(payload) } diff --git a/packages/koa/tests/fixtures/sub/contract/contract.json b/packages/koa/tests/fixtures/sub/contract/contract.json deleted file mode 100644 index 0b53f8751a4ac515ced6c67ef39d80d0b31a17a1..0000000000000000000000000000000000000000 --- a/packages/koa/tests/fixtures/sub/contract/contract.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "query": { - "msService": { - "file": "/home/joel/projects/open-source/jsonql/packages/koa/tests/fixtures/sub/resolver/query/ms-service.js", - "description": false, - "params": [ - { - "type": [ - "string" - ], - "name": "msg", - "description": "incoming message" - } - ], - "returns": [ - { - "type": [ - "string" - ], - "description": "out going message" - } - ] - } - }, - "mutation": { - "updateMsSerivce": { - "file": "/home/joel/projects/open-source/jsonql/packages/koa/tests/fixtures/sub/resolver/mutation/update-ms-serivce.js", - "description": "create a mutation to test why the call said the payload already declared", - "params": [ - { - "type": [ - "string" - ], - "name": "payload", - "description": "incoming" - } - ], - "returns": [ - { - "type": [ - "string" - ], - "description": "output" - } - ] - } - }, - "auth": {}, - "timestamp": 1566213707037, - "sourceType": "script" -} diff --git a/packages/koa/tests/fixtures/sub/contract/public-contract.json b/packages/koa/tests/fixtures/sub/contract/public-contract.json deleted file mode 100644 index 85559afe3fcd71111ea6c83ec5a1a0c16ea03126..0000000000000000000000000000000000000000 --- a/packages/koa/tests/fixtures/sub/contract/public-contract.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "query": { - "helloWorld": { - "description": "This is the stock resolver for testing purpose", - "params": [], - "returns": [ - { - "type": "string", - "description": "stock message" - } - ] - }, - "msService": { - "description": false, - "params": [ - { - "type": [ - "string" - ], - "name": "msg", - "description": "incoming message" - } - ], - "returns": [ - { - "type": [ - "string" - ], - "description": "out going message" - } - ] - } - }, - "mutation": { - "updateMsSerivce": { - "description": "create a mutation to test why the call said the payload already declared", - "params": [ - { - "type": [ - "string" - ], - "name": "payload", - "description": "incoming" - } - ], - "returns": [ - { - "type": [ - "string" - ], - "description": "output" - } - ] - } - }, - "auth": {}, - "timestamp": 1566213707037 -} diff --git a/packages/koa/tests/fixtures/sub/resolver/mutation/update-ms-service.js b/packages/koa/tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js similarity index 76% rename from packages/koa/tests/fixtures/sub/resolver/mutation/update-ms-service.js rename to packages/koa/tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js index d53bd1b0aacc946daa5ea819cb4782fa6144a186..9da096d76e30733a278ed335a48dc1023d72bc24 100644 --- a/packages/koa/tests/fixtures/sub/resolver/mutation/update-ms-service.js +++ b/packages/koa/tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js @@ -3,6 +3,6 @@ * @param {string} payload incoming * @return {string} output */ -module.exports = function updateMsService(payload) { +module.exports = function subUpdateMsService(payload) { return payload + ' updated'; } diff --git a/packages/koa/tests/fixtures/sub/resolver/query/ms-service.js b/packages/koa/tests/fixtures/sub/resolver/query/sub-ms-service.js similarity index 81% rename from packages/koa/tests/fixtures/sub/resolver/query/ms-service.js rename to packages/koa/tests/fixtures/sub/resolver/query/sub-ms-service.js index 460f4e9a5e66d5754a980870aa10ea0946f7e78a..c8c0a047fa5884ae8af8996c361c332828a82daa 100644 --- a/packages/koa/tests/fixtures/sub/resolver/query/ms-service.js +++ b/packages/koa/tests/fixtures/sub/resolver/query/sub-ms-service.js @@ -3,7 +3,7 @@ const debug = require('debug')('jsonql-koa:query:ms-service') * @param {string} msg incoming message * @return {string} out going message */ -module.exports = function msService(msg) { +module.exports = function subMsService(msg) { debug('msg', msg) diff --git a/packages/koa/tests/helpers/server.js b/packages/koa/tests/helpers/server.js index 166a8850e9c3420a2ad1bd3330e48462e537ce3f..2c20f0697608662097b90e6280cb5dd2edeac600 100755 --- a/packages/koa/tests/helpers/server.js +++ b/packages/koa/tests/helpers/server.js @@ -1,11 +1,11 @@ // this will export the server for other test to use // const test = require('ava'); -const Koa = require('koa'); -const { join } = require('path'); -const bodyparser = require('koa-bodyparser'); -const jsonqlMiddleware = require(join(__dirname, '..', '..','index')); -const { type, headers, dirs } = require('../fixtures/options'); -const fsx = require('fs-extra'); +const Koa = require('koa') +const { join } = require('path') +const bodyparser = require('koa-bodyparser') +const jsonqlMiddleware = require(join(__dirname, '..', '..','index')) +const { type, headers, dirs } = require('../fixtures/options') +const fsx = require('fs-extra') const myKey = '4670994sdfkl'; // add a dir to seperate the contract files module.exports = (config={}, dir = '') => { diff --git a/packages/koa/tests/helpers/sub-server.js b/packages/koa/tests/helpers/sub-server.js new file mode 100644 index 0000000000000000000000000000000000000000..aef5991064f15350a6b66c678c98c9c78fb559d7 --- /dev/null +++ b/packages/koa/tests/helpers/sub-server.js @@ -0,0 +1,24 @@ +const { join } = require('path') +const fixturesDir = join(__dirname, '..', 'fixtures') + +const serverIoCore = require('server-io-core') +const jsonqlKoa = require('../../index') + +function startSubServer(msPort) { + return serverIoCore({ + webroot: join(fixturesDir, 'html'), + socket:false, + open:false, + debugger: false, + port: msPort, + middlewares: [ + jsonqlKoa({ + name: `server${msPort}`, + contractDir: join(fixturesDir, 'tmp', `sub-server-${msPort}`), + resolverDir: join(fixturesDir, 'sub', 'resolver') + }) + ] + }) +} + +module.exports = startSubServer diff --git a/packages/koa/tests/node-client.test.js b/packages/koa/tests/node-client.donttest.js similarity index 54% rename from packages/koa/tests/node-client.test.js rename to packages/koa/tests/node-client.donttest.js index 4d50ac4cc888d196f3b8f084f4851aba7c880783..c749becfb686ee48801ba099c8ed97a42277fd3e 100644 --- a/packages/koa/tests/node-client.test.js +++ b/packages/koa/tests/node-client.donttest.js @@ -9,34 +9,28 @@ const serverIoCore = require('server-io-core') const jsonqlKoa = require('../') const hello = require('./helpers/hello') const baseDir = join(__dirname, 'fixtures') -const msPort = 6001; const clientContractDir = join(__dirname, 'fixtures', 'tmp', 'client6002') const createServer = require('./helpers/server') + +const port = 6002; const dir = 'server6002'; +const msPort = 8001; +const startSubServer = require('./helpers/sub-server') + // base test setup test.before(async t => { t.context.baseApp = createServer({ + name: `server${port}`, clientConfig: [{ - hostname: 'http://localhost:6002', + hostname: `http://localhost:${msPort}`, name: 'client0' }] }, dir) - t.context.baseServer = t.context.baseApp.listen(6002) + t.context.baseServer = t.context.baseApp.listen(port) + + const { app, stop } = startSubServer(msPort) - const { app, stop } = serverIoCore({ - webroot: join(baseDir, 'html'), - socket:false, - open:false, - debugger: false, - port: msPort, - middlewares: [ - jsonqlKoa({ - contractDir: join(baseDir, 'sub', 'contract'), - resolverDir: join(baseDir, 'sub', 'resolver') - }) - ] - }) t.context.app = app t.context.stop = stop }) @@ -44,35 +38,33 @@ test.before(async t => { test.after(t => { t.context.stop() t.context.baseServer.close() - // fsx.removeSync(clientContractDir) - // fsx.removeSync(join(baseDir, 'tmp', dir)) + fsx.removeSync(clientContractDir) + fsx.removeSync(join(baseDir, 'tmp', dir)) }) -test(`First test both server is running`, async t => { +test.skip(`First test both server is running`, async t => { const res1 = await hello(t.context.baseApp) t.is(res1.status, 200) const res2 = await hello(t.context.app) t.is(res2.status, 200) }) -test.only(`It should able to call a resolver that access another ms`, async t => { - +test.skip(`First test calling the 6001 directly with the mutation call`, async t => { const client = await nodeClient({ - hostname: 'http://localhost:6001', - contractDir: join(__dirname, 'fixtures', 'tmp', 'client6001') + hostname: `http://localhost:${msPort}`, + contractDir: join(__dirname, 'fixtures', 'tmp', `client${msPort}`) }) + const result = await client.query.subMsService('testing') + t.truthy(result.indexOf(`ms service`)) +}) - const result = await client.mutation.updateMsSerivce('testing') - - /* +test(`It should able to call a resolver that access another ms`, async t => { + // the problem now is calling the 6001 but received the 8001 public contract? const client = await nodeClient({ - hostname: 'http://localhost:6002', + hostname: `http://localhost:${port}`, contractDir: clientContractDir }) - // debug(client) - const result = await client.mutation.updateMsService('testing') - */ - - t.truthy(result.indexOf(`ms service`)) + const result = await client.mutation.updateMsService('testing') + t.truthy(result.indexOf(`ms service`)) }) diff --git a/packages/node-client/index.js b/packages/node-client/index.js index ceba0435a14a434c1b0c7e4b25d832c3a24ad843..f33951ecfb7dc3e601d6cbc57a68607ec9ad6193 100755 --- a/packages/node-client/index.js +++ b/packages/node-client/index.js @@ -5,8 +5,7 @@ const { generator, checkOptions } = require('./src') - -// const debug = require('debug')('jsonql-node-client:index'); +const debug = require('debug')('jsonql-node-client:main') // finally /** * The config takes two things @@ -17,6 +16,10 @@ const { */ module.exports = function(config) { return checkOptions(config) + .then(opts => { + debug('[jsonql-node-client] init opts', opts) + return opts; + }) .then(opts => ( { jsonqlInstance: new JsonqlRequestClient(opts), diff --git a/packages/node-client/package.json b/packages/node-client/package.json index 95cbc78ca6f91b0cc8578a8764bad344a7e40856..5af72c0f8c18f395f88bae3a3cd8e2872ee1e26f 100755 --- a/packages/node-client/package.json +++ b/packages/node-client/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-node-client", - "version": "1.1.6", + "version": "1.1.7", "description": "jsonql node.js client using request", "main": "index.js", "scripts": { @@ -10,7 +10,8 @@ "test:auth": "DEBUG=jsonql-* ava tests/auth.test.js", "test:valid": "DEBUG=jsonql-node-client* ava tests/validation.test.js", "test:config": "DEBUG=jsonql-node-client* ava tests/config.test.js", - "test:jwt": "DEBUG=jsonql-node-client* ava tests/jwt.test.js" + "test:jwt": "DEBUG=jsonql-node-client* ava tests/jwt.test.js", + "test:contract": "DEBUG=jsonql-node-client:main,jsonql-koa:process-contract ava --verbose tests/contract.test.js" }, "repository": { "type": "git", diff --git a/packages/node-client/src/cache.js b/packages/node-client/src/cache.js deleted file mode 100644 index 8a8e666e3ce4e7b1a0a795194fe8b7134338e95e..0000000000000000000000000000000000000000 --- a/packages/node-client/src/cache.js +++ /dev/null @@ -1,12 +0,0 @@ -// using node-cache for storage -const NodeCache = require('node-cache') -const nc = new NodeCache() - -const getter = key => nc.get(key) - -const setter = (key, value) => nc.set(key, value) - -module.exports = { - getter, - setter -} diff --git a/packages/node-client/src/jsonql/get-remote-contract.js b/packages/node-client/src/jsonql/get-remote-contract.js index 8efecfe77e04a54167eb7b2ec1c2afbc91f251d6..0ec0d9649cca2701c2b348233446d91fc3a7c443 100755 --- a/packages/node-client/src/jsonql/get-remote-contract.js +++ b/packages/node-client/src/jsonql/get-remote-contract.js @@ -12,8 +12,12 @@ const { const { getDebug } = require('../utils') const debug = getDebug('get-remote-contract') -// export it -module.exports = function getRemoteContract(args) { +/** + * @param {object} args argument options + * @param {function} cb callback + * @return {promise} + */ +module.exports = function getRemoteContract(args, cb) { return new Promise((resolver, rejecter) => { // defintely we have the remote or not here if (!args.remote) { @@ -41,13 +45,15 @@ module.exports = function getRemoteContract(args) { if (args.raw) { return resolver(contract) } + // cache it + cb(contract) fsx.outputJson(outFile, contract, {spaces: 2}, err => { if (err) { return rejecter(err) } const result = args.returnAs && args.returnAs === 'file' ? outFile : contract; resolver(result) - }); + }) } } // execute the remote call diff --git a/packages/node-client/src/jsonql/jsonql-base-cls.js b/packages/node-client/src/jsonql/jsonql-base-cls.js index 8d9e9373bbc3a7917be13ed8e1e26c240ba64ce4..076e5b890430f068353e4f1e95cf08598c0268d9 100755 --- a/packages/node-client/src/jsonql/jsonql-base-cls.js +++ b/packages/node-client/src/jsonql/jsonql-base-cls.js @@ -13,17 +13,19 @@ const merge = require('lodash.merge') const { AUTH_HEADER , BEARER } = require('jsonql-constants') // using node-cache from v1.1.0 -const { getter, setter } = require('../cache') +// it becomes a class since 1.1.7 +const JsonqlCacheClass = require('./jsonql-cache-class') const getRemote = require('./get-remote-contract') const { getDebug } = require('../utils') const debug = getDebug('jsonql-base-cls') -class JsonqlClient { +class JsonqlClient extends JsonqlCacheClass { constructor(config) { + super(config) this.opts = config // @TODO we need to figure out an alternative way to store the session data - this.__store__ = {}; + this.__store__ = {}; // @TODO remove this later this.__url__ = [this.opts.hostname, this.opts.jsonqlPath].join('/') } @@ -139,15 +141,28 @@ class JsonqlClient { // first check if we have a contract already in memory if (contract && typeof contract === 'object' && (contract.query || contract.mutation)) { debug('return contract from opts') + this.setter('contract', contract) if (!this.__isContractExpired(contract)) { return Promise.resolve(contract) } } + // new in v1.1.7 read from cache + let cacheContract = this.getter('contract') + if (cacheContract) { + if (this.__isContractExpired(cacheContract)) { + this.setter('contract', false) // just clear it out + } else { + debug(`get contract from cache`) + return Promise.resolve(cacheContract) + } + } + // check if there is a contract store locally const file = join(this.opts.contractDir, this.opts.contractFileName); if (fsx.existsSync(file)) { debug('return contract from file: ', file) if (!this.__isContractExpired(contract)) { + this.setter('contract', contract) // cache it return Promise.resolve(fsx.readJsonSync(file)) } } @@ -161,7 +176,9 @@ class JsonqlClient { return getRemote(Object.assign({ remote: this.__url__, out: this.opts.contractDir - }, { authHeader })) + }, { authHeader }), contract => { + this.setter('contract', contract) + }) } /** @@ -169,7 +186,7 @@ class JsonqlClient { * @return {string} token */ __storeAuthToken(token) { - let r = setter('token', token) ? token : false; + let r = this.setter('token', token) ? token : false; debug('store token --> ', r) return r; } @@ -188,7 +205,7 @@ class JsonqlClient { * @return {string} auth token */ __getAuthToken() { - let v = getter('token') + let v = this.getter('token') debug('get token from node-cache', v) return v; } diff --git a/packages/node-client/src/jsonql/jsonql-cache-class.js b/packages/node-client/src/jsonql/jsonql-cache-class.js new file mode 100644 index 0000000000000000000000000000000000000000..7bf1f8cb403e34ecd470c008875049bc36fef85e --- /dev/null +++ b/packages/node-client/src/jsonql/jsonql-cache-class.js @@ -0,0 +1,19 @@ +// using node-cache for storage +const NodeCache = require('node-cache') + +class JsonqlCacheClass { + constructor() { + this.nc = new NodeCache() + } + + getter(key) { + return this.nc.get(key) + } + + setter(key, value) { + return this.nc.set(key,value) + } +} + + +module.exports = JsonqlCacheClass diff --git a/packages/node-client/src/jsonql/request-client.js b/packages/node-client/src/jsonql/request-client.js index 4d7220cabc05fa311c945016c9d58366ecc60245..9e4f800f4ee6999c25b02d611077ec02bd8ce2d3 100755 --- a/packages/node-client/src/jsonql/request-client.js +++ b/packages/node-client/src/jsonql/request-client.js @@ -23,7 +23,7 @@ class JsonqlRequestClient extends JsonqlClient { getContract() { return this.__readContract().then(result => { if (typeof result === 'string') { - return fsx.readJsonSync(result); + return fsx.readJsonSync(result) } return result; }) diff --git a/packages/node-client/tests/contract.test.js b/packages/node-client/tests/contract.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a4e4253af7ca20ec8b559de7098c3ef3d542f7ae --- /dev/null +++ b/packages/node-client/tests/contract.test.js @@ -0,0 +1,85 @@ +// a new test to check if we have two setup on two different port +// what happen with the middleware +const test = require('ava') +const fsx = require('fs-extra') +const client = require('../index') +const server = require('./fixtures/two/server-setup') +const { join } = require('path') +const baseDir = join(__dirname, 'fixtures', 'two') +const chain = fn => Promise.resolve(fn) +const portA = 7007; +const portB = 8008; +const host = 'http://localhost:' +const contract_a = join(baseDir, 'tmp', 'a') +const contract_b = join(baseDir, 'tmp', 'b') + +const debug = require('debug')('jsonql-node-client:test:contract') + +test.before(async t => { + t.context.client_A = await chain( + server(portA, join(baseDir, 'resolvera'), contract_a) + ).then(a => { + let { name } = a; + let app = a[name].app + t.context.app_A = app + t.context.stop_A = a[name].stop + return app; + }).then(app => { + return client({ + hostname: `${host}${portA}`, + contractDir: join(baseDir, 'tmp', 'a', 'client') + }) + }) + + t.context.client_B = await chain( + server(portB, join(baseDir, 'resolverb'), contract_b) + ).then(b => { + let { name } = b; + let app = b[name].app + t.context.app_B = app + t.context.stop_B = b[name].stop + return app + }).then(app => { + return client({ + hostname: `${host}${portB}`, + contractDir: join(baseDir, 'tmp', 'b', 'client') + }) + }) +}) + +test.after(t => { + + t.context.stop_A() + t.context.stop_B() + + fsx.removeSync(contract_a) + fsx.removeSync(contract_b) +}) + +test(`It should able to say hello to server B`, async t => { + const c = t.context.client_B; + const result1 = await c.query.helloWorld() + t.truthy(result1.indexOf('world')) + const result2 = await c.query.getterB() + t.is(result2, 'B') +}) + +test(`It should able to say hello to server A`, async t => { + const c = t.context.client_A; + const result1 = await c.query.helloWorld() + t.truthy(result1.indexOf('world')) + const result2 = await c.query.getterA() + t.is(result2, 'A') +}) + +test(`It should able to call server A mutation`, async t => { + const c = t.context.client_A + const result1 = await c.mutation.saverA('A') + t.is(result1, true) +}) + +test(`It should able to call server B mutation`, async t => { + const c = t.context.client_B + const result1 = await c.mutation.saverB('B') + t.is(result1, true) +}) diff --git a/packages/node-client/tests/fixtures/two/dummy/index.html b/packages/node-client/tests/fixtures/two/dummy/index.html new file mode 100644 index 0000000000000000000000000000000000000000..fd86e9cecae71449fe81d662fb4d45193c29f5c5 --- /dev/null +++ b/packages/node-client/tests/fixtures/two/dummy/index.html @@ -0,0 +1,9 @@ + + + + Dummy + + +

Dummy

+ + diff --git a/packages/node-client/tests/fixtures/two/resolvera/mutation/saver-a.js b/packages/node-client/tests/fixtures/two/resolvera/mutation/saver-a.js new file mode 100644 index 0000000000000000000000000000000000000000..1faf1ef42dac544a4c6497eb46cbe23ef25edfd0 --- /dev/null +++ b/packages/node-client/tests/fixtures/two/resolvera/mutation/saver-a.js @@ -0,0 +1,8 @@ +/** + * simeple save A + * @param {string} payload + * @return {boolean} when match + */ +module.exports = function saverB(payload) { + return payload === 'A' +} diff --git a/packages/node-client/tests/fixtures/two/resolvera/query/getter-a.js b/packages/node-client/tests/fixtures/two/resolvera/query/getter-a.js new file mode 100644 index 0000000000000000000000000000000000000000..0e168b9904c68eb07dcd79050fb53d387805402b --- /dev/null +++ b/packages/node-client/tests/fixtures/two/resolvera/query/getter-a.js @@ -0,0 +1,7 @@ +/** + * Just return a message A + * @return {string} message A + */ +module.exports = function getterB() { + return `A` +} diff --git a/packages/node-client/tests/fixtures/two/resolverb/mutation/saver-b.js b/packages/node-client/tests/fixtures/two/resolverb/mutation/saver-b.js new file mode 100644 index 0000000000000000000000000000000000000000..3fd8d8017215ca93aabcf2587c19855778c27717 --- /dev/null +++ b/packages/node-client/tests/fixtures/two/resolverb/mutation/saver-b.js @@ -0,0 +1,8 @@ +/** + * simeple save B + * @param {string} payload + * @return {boolean} when match + */ +module.exports = function saverB(payload) { + return payload === 'B' +} diff --git a/packages/node-client/tests/fixtures/two/resolverb/query/getter-b.js b/packages/node-client/tests/fixtures/two/resolverb/query/getter-b.js new file mode 100644 index 0000000000000000000000000000000000000000..974f7ebf8a76dad16157be88c906ad37831171c3 --- /dev/null +++ b/packages/node-client/tests/fixtures/two/resolverb/query/getter-b.js @@ -0,0 +1,7 @@ +/** + * Just return a message B + * @return {string} message B + */ +module.exports = function getterB() { + return `B` +} diff --git a/packages/node-client/tests/fixtures/two/server-setup.js b/packages/node-client/tests/fixtures/two/server-setup.js new file mode 100644 index 0000000000000000000000000000000000000000..d4721725d1754b1922bc7bb13da6f9a1afc4b46c --- /dev/null +++ b/packages/node-client/tests/fixtures/two/server-setup.js @@ -0,0 +1,27 @@ +const server = require('server-io-core') +const koa = require('../../../../koa') +const { join } = require('path') +const dummy = join(__dirname, 'dummy') + +module.exports = (port, resolverDir, contractDir) => { + const name = `server${port}` + const { app, stop } = server({ + webroot: dummy, + open: false, + debugger: false, + reload: false, + socket: false, + port: port, + middlewares: [ + koa({ + name, + resolverDir, + contractDir + }) + ] + }) + return { + name, + [name]: {app, stop} + } +} diff --git a/packages/resolver/package.json b/packages/resolver/package.json index 5331838cb183d7571926865ed6d745aa088c78b2..b54ec98e297f087e46ce37617a65ea07b1e51f04 100644 --- a/packages/resolver/package.json +++ b/packages/resolver/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-resolver", - "version": "0.6.2", + "version": "0.6.5", "description": "This is NOT for general use, please do not install it directly. This module is part of the jsonql tools supporting modules.", "main": "index.js", "files": [ diff --git a/packages/resolver/src/client/inject-node-clients.js b/packages/resolver/src/client/inject-node-clients.js index d8abe5c6cd4fb1b46dd1945c4a51944c4d84ac0a..aee6aa5afab2237120ed432c22747d6959e6d6e8 100644 --- a/packages/resolver/src/client/inject-node-clients.js +++ b/packages/resolver/src/client/inject-node-clients.js @@ -1,5 +1,6 @@ const { getDebug } = require('../utils') const debug = getDebug(`inject-node-clients`) +const name = 'client'; /** * kind of curry the function back to inject into the resolver * @param {array} clients the node clients @@ -9,19 +10,20 @@ function resolveClients(clients) { /** * When pass as number then check this index, if its name then * find with the name property, all failed then return false - * @param {number|string} + * @param {number|string} name to id the client could be undefined when there is only one * @return {boolean|object} false when failed */ return function(name) { debug(`resolveClients ${name}`, clients) - if (typeof name === 'string') { + if ((name === undefined || name === null) && clients.length === 1) { + return clients[0] + } else if (typeof name === 'string') { return clients .filter(client => client.name === name) .reduce((base, result) => { return result || base; }, false) - } - if (clients[name]) { + } else if (clients[name]) { return clients[name] } return false; @@ -35,8 +37,8 @@ function resolveClients(clients) { * @return {function} the injected resolver */ module.exports = function injectNodeClient(resolver, clients) { - if (Object.getOwnPropertyDescriptor(resolver, 'clients') === undefined) { - Object.defineProperty(resolver, 'clients', { + if (Object.getOwnPropertyDescriptor(resolver, name) === undefined) { + Object.defineProperty(resolver, name, { value: resolveClients(clients), writable: false // make this immutatble }) diff --git a/packages/resolver/src/resolve-methods.js b/packages/resolver/src/resolve-methods.js index bcfa0d134a4a7cf5dbeeff5e200a0293a65dc856..381c8c7331b49813b6d4c987b5bb4d7111bf6360 100644 --- a/packages/resolver/src/resolve-methods.js +++ b/packages/resolver/src/resolve-methods.js @@ -10,14 +10,21 @@ const { UNKNOWN_ERROR } = require('jsonql-errors') const { provideUserdata } = require('jsonql-jwt') -const { MODULE_TYPE } = require('jsonql-constants') +const { + MODULE_TYPE, + DEFAULT_RESOLVER_IMPORT_FILE_NAME, + QUERY_NAME, + MUTATION_NAME, + PAYLOAD_PARAM_NAME, + CONDITION_PARAM_NAME, + RESOLVER_PARAM_NAME , + QUERY_ARG_NAME +} = require('jsonql-constants') const { getDebug, handleOutput, - extractArgsFromPayload, ctxErrorHandler, - packResult, - importFromModule + packResult } = require('./utils') const searchResolvers = require('./search-resolvers') const validateAndCall = require('./validate-and-call') @@ -25,6 +32,39 @@ const provideNodeClients = require('./provide-node-clients') const debug = getDebug('resolve-method') +/** + * Extract the args from the payload + * @param {object} payload to work with + * @param {string} type of call + * @return {array} args + */ +const extractArgsFromPayload = function(payload, type) { + switch (type) { + case QUERY_NAME: + return payload[QUERY_ARG_NAME]; + case MUTATION_NAME: + return [ + payload[PAYLOAD_PARAM_NAME], + payload[CONDITION_PARAM_NAME] + ]; + default: + throw new JsonqlError(`Unknown ${type} to extract argument from!`) + } +} + +/** + * New for ES6 module features + * @param {string} resolverDir resolver directory + * @param {string} type of resolver + * @param {string} resolverName name of resolver + * @return {function} the imported resolver + */ +function importFromModule(resolverDir, type, resolverName) { + debug('[importFromModule]', resolverDir, type, resolverName) + const resolvers = require( join(resolverDir, DEFAULT_RESOLVER_IMPORT_FILE_NAME) ) + return resolvers[type + resolverName] +} + /** * A new method breaking out the get resolver and prepare code * then make the original resolveMethod as a koa render handler @@ -50,7 +90,7 @@ const executeResolver = async (opts, type, resolverName, payload, contract, user fn = await provideNodeClients(fn, opts) // here we could apply the userdata to the method const result = await validateAndCall( - provideUserdata(fn, userdata), // always call it @TODO need to provide the nodeClient as well + provideUserdata(fn, userdata), // always call this one even auth is false args, contract, type, diff --git a/packages/resolver/src/search-resolvers.js b/packages/resolver/src/search-resolvers.js index b986b10ba760cb82f376c140c56ebaf26019354f..43cb2787ac20346f25d83684201a969a5a521573 100644 --- a/packages/resolver/src/search-resolvers.js +++ b/packages/resolver/src/search-resolvers.js @@ -3,11 +3,36 @@ const fs = require('fs') const { join } = require('path') const { JsonqlResolverNotFoundError } = require('jsonql-errors') -const { getPathToFn, getDebug } = require('./utils') +const { getDebug } = require('./utils') const debug = getDebug('search-resolvers') const prod = process.env.NODE_ENV === 'production'; +/** + * @param {string} name + * @param {string} type + * @param {object} opts + * @return {function} + */ +const getPathToFn = function(name, type, opts) { + const dir = opts.resolverDir; + const fileName = dasherize(name); + let paths = []; + if (opts.contract && opts.contract[type] && opts.contract[type].path) { + paths.push(opts.contract[type].path) + } + paths.push( join(dir, type, fileName, 'index.js') ) + paths.push( join(dir, type, fileName + '.js') ) + + const ctn = paths.length; + for (let i=0; i ( - trim(str) + (str+'') + .trim() .replace(/([A-Z])/g, '-$1') .replace(/[-_\s]+/g, '-') .toLowerCase() @@ -61,31 +53,6 @@ const inArray = (arr, value) => !!arr.filter(a => a === value).length; */ const getDocLen = doc => Buffer.byteLength(doc, 'utf8') -/** - * @param {string} name - * @param {string} type - * @param {object} opts - * @return {function} - */ -const getPathToFn = function(name, type, opts) { - const dir = opts.resolverDir; - const fileName = dasherize(name); - let paths = []; - if (opts.contract && opts.contract[type] && opts.contract[type].path) { - paths.push(opts.contract[type].path) - } - paths.push( join(dir, type, fileName, 'index.js') ) - paths.push( join(dir, type, fileName + '.js') ) - - const ctn = paths.length; - for (let i=0; i