diff --git a/lib/bus.js b/lib/bus.js index e0bf43c1..84898932 100644 --- a/lib/bus.js +++ b/lib/bus.js @@ -4,27 +4,44 @@ const { metarhia } = require('./deps.js'); const prepare = (unit, application) => { const namespaces = application.schemas ? [application.schemas.model] : []; - const { parameters, returns } = unit; + const { parameters, query = {}, returns } = unit; const { Schema } = metarhia.metaschema; const validation = { parameters: parameters ? Schema.from(parameters, namespaces) : null, + query: query.params ? Schema.from(query.params, namespaces) : null, returns: returns ? Schema.from(returns, namespaces) : null, }; - const method = async (args) => { - const { parameters, returns } = validation; + const method = async (args = {}) => { + const { parameters, query, returns } = validation; if (parameters) { const { valid, errors } = parameters.check(args); const problems = errors.join('; '); if (!valid) return new Error('Invalid parameters type: ' + problems); } + if (unit.query.params) { + const { valid, errors } = query.check(args); + const problems = errors.join('; '); + if (!valid) return new Error('Invalid query type: ' + problems); + } const service = method.parent['.service']; const verb = unit.method.get ? 'get' : 'post'; const target = [service.url, unit.method[verb]]; if (unit.method.path) { target.push(...unit.method.path.map((arg) => args[arg])); } + let url = target.join('/'); + if (unit.query) { + const params = []; + const { prefix = '', suffix = '' } = unit.query; + for (const param of Object.keys(unit.query.params)) { + if (!args[param]) continue; + params.push([prefix + param + suffix, args[param]]); + } + const parsedParams = Object.fromEntries(params); + const stringParams = new URLSearchParams(parsedParams).toString(); + url = params.length ? url + '?' + stringParams : url; + } const body = metarhia.metautil.serializeArguments(unit.method.body, args); - const url = target.join('/'); const options = { method: verb.toUpperCase(), body }; const result = await metarhia.metautil.httpApiCall(url, options); if (returns) { diff --git a/test/bus.js b/test/bus.js index a5b46c05..82913baf 100644 --- a/test/bus.js +++ b/test/bus.js @@ -23,7 +23,7 @@ metatests.testAsync('lib/bus', async (test) => { test.strictSame(typeof bus.application, 'object'); test.strictSame(bus.tree, {}); await bus.load(); - test.strictSame(Object.keys(bus.tree), ['math', 'worldTime']); + test.strictSame(Object.keys(bus.tree), ['fakerapi', 'math', 'worldTime']); test.strictSame(bus.tree.math.parent, bus.tree); test.strictSame(typeof bus.tree.math, 'object'); test.strictSame(typeof bus.tree.math.eval, 'function'); diff --git a/test/bus/fakerapi/.service.js b/test/bus/fakerapi/.service.js new file mode 100644 index 00000000..4c449dd1 --- /dev/null +++ b/test/bus/fakerapi/.service.js @@ -0,0 +1,7 @@ +({ + url: 'https://fakerapi.it', + limits: [ + { calls: 10, per: '1m' }, + { calls: 10000, per: '1d' }, + ], +}); diff --git a/test/bus/fakerapi/books.js b/test/bus/fakerapi/books.js new file mode 100644 index 00000000..e756d85c --- /dev/null +++ b/test/bus/fakerapi/books.js @@ -0,0 +1,32 @@ +({ + method: { + get: 'api/v1/books', + }, + + query: { + prefix: '_', + params: { + quantity: '?number', + }, + }, + + returns: { + status: 'string', + code: 'number', + total: 'number', + data: { + type: 'array', + value: { + id: 'number', + title: 'string', + author: 'string', + genre: 'string', + description: 'string', + isbn: 'string', + image: 'string', + published: 'string', + publisher: 'string', + }, + }, + }, +});