Split interface creation (#50)

* Split interface creation

* Lint fixes

* Update @polkadot dependencies
This commit is contained in:
Jaco Greeff
2018-01-25 15:19:56 +01:00
committed by GitHub
parent 20f120fccd
commit 263289a343
16 changed files with 208 additions and 283 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-format",
"version": "0.6.12",
"version": "0.7.0",
"description": "Input/Output formatters for JsonRPC exchange",
"main": "index.js",
"keywords": [
@@ -30,11 +30,11 @@
"test": "echo \"Tests only available from root wrapper\""
},
"devDependencies": {
"@polkadot/api-jsonrpc": "^0.6.12"
"@polkadot/api-jsonrpc": "^0.7.0"
},
"dependencies": {
"@polkadot/primitives-json": "^0.4.6",
"@polkadot/util": "^0.11.1",
"@polkadot/primitives-json": "^0.4.10",
"@polkadot/util": "^0.13.1",
"babel-runtime": "^6.26.0"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-jsonrpc",
"version": "0.6.12",
"version": "0.7.0",
"description": "Method definitions for the Polkadot RPC layer",
"main": "index.js",
"engines": {
+2 -2
View File
@@ -3,7 +3,7 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { InterfaceDefinition } from './types';
import type { InterfaceDefinitions } from './types';
const chain = require('./chain');
const state = require('./state');
@@ -14,4 +14,4 @@ const state = require('./state');
module.exports = ({
chain,
state
}: { [string]: InterfaceDefinition });
}: InterfaceDefinitions);
+6
View File
@@ -22,8 +22,14 @@ export type InterfaceMethodDefinition = {
output: InterfaceOutputType
};
export type InterfaceTypes = 'chain' | 'state';
export type InterfaceDefinition = {
methods: {
[string]: InterfaceMethodDefinition
}
};
export type InterfaceDefinitions = {
[InterfaceTypes]: InterfaceDefinition
};
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-provider",
"version": "0.6.12",
"version": "0.7.0",
"description": "Transport providers for the API",
"main": "index.js",
"keywords": [
@@ -34,7 +34,7 @@
"nock": "^9.1.0"
},
"dependencies": {
"@polkadot/util": "^0.11.1",
"@polkadot/util": "^0.13.1",
"babel-runtime": "^6.26.0",
"isomorphic-fetch": "^2.2.1",
"websocket": "^1.0.25"
@@ -24,6 +24,7 @@ module.exports = class JsonRpcCoder {
throw new Error(`[${code}]: ${message}`);
}
assert(!isUndefined(response.result), 'No result found in JsonRpc response');
return response.result;
+3 -15
View File
@@ -207,28 +207,16 @@ describe('Ws', () => {
});
describe('queued', () => {
let sendPromise;
beforeEach(() => {
ws = createWs([{
it('sends messages when connected', () => {
const ws = createWs([{
id: 1,
method: 'test_queue',
reply: {
result: 'ok'
}
}], false);
sendPromise = ws.send('test_queue', []);
});
const sendPromise = ws.send('test_queue', []);
it('sends messages when connected', () => {
ws.connect();
return sendPromise.then((result) => {
expect(result).toEqual('ok');
});
});
it('sends messages when connected (errors)', () => {
ws.connect();
return sendPromise.then((result) => {
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api",
"version": "0.6.12",
"version": "0.7.0",
"description": "A JavaScript wrapper for the Polkadot JsonRPC interface",
"main": "index.js",
"keywords": [
@@ -30,10 +30,10 @@
"test": "echo \"Tests only available from root wrapper\""
},
"dependencies": {
"@polkadot/api-format": "^0.6.12",
"@polkadot/api-jsonrpc": "^0.6.12",
"@polkadot/api-provider": "^0.6.12",
"@polkadot/util": "^0.11.1",
"@polkadot/api-format": "^0.7.0",
"@polkadot/api-jsonrpc": "^0.7.0",
"@polkadot/api-provider": "^0.7.0",
"@polkadot/util": "^0.13.1",
"babel-runtime": "^6.26.0"
}
}
+6 -47
View File
@@ -4,63 +4,22 @@
// @flow
import type { ProviderInterface } from '@polkadot/api-provider/types';
import type { InterfaceDefinition } from '@polkadot/api-jsonrpc/types';
import type { ApiInterface, ApiInterface$Section } from './types';
const { formatInputs, formatOutput } = require('@polkadot/api-format');
const interfaces = require('@polkadot/api-jsonrpc');
const assert = require('@polkadot/util/assert');
const ExtError = require('@polkadot/util/ext/error');
const isFunction = require('@polkadot/util/is/function');
const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature');
const createInterface = require('./create/interface');
module.exports = class Api implements ApiInterface {
_provider: ProviderInterface;
_chainInterface: ApiInterface$Section;
_stateInterface: ApiInterface$Section;
chain: ApiInterface$Section;
state: ApiInterface$Section;
constructor (provider: ProviderInterface) {
assert(provider && isFunction(provider.send), 'Expected Provider');
this._provider = provider;
this._chainInterface = this._createInterface(interfaces, 'chain');
this._stateInterface = this._createInterface(interfaces, 'state');
}
// flowlint-next-line unsafe-getters-setters:off
get chain (): ApiInterface$Section {
return this._chainInterface;
}
// flowlint-next-line unsafe-getters-setters:off
get state (): ApiInterface$Section {
return this._stateInterface;
}
_createInterface (definitions: { [string]: InterfaceDefinition }, section: string): ApiInterface$Section {
const definition = definitions[section];
return Object
.keys(definition.methods)
.reduce((container, method: string) => {
const { inputs, output } = definition.methods[method];
const rpcName = `${section}_${method}`;
container[method] = async (..._params: Array<mixed>): Promise<mixed> => {
try {
assert(inputs.length === _params.length, `${inputs.length} params expected, found ${_params.length} instead`);
const params = formatInputs(inputs, _params);
const result = await this._provider.send(rpcName, params);
return formatOutput(output, result);
} catch (error) {
throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code);
}
};
return container;
}, {});
this.chain = createInterface(provider, interfaces.chain, 'chain');
this.state = createInterface(provider, interfaces.state, 'state');
}
};
+9 -75
View File
@@ -2,8 +2,6 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const isFunction = require('@polkadot/util/is/function');
const Api = require('./api');
describe('Api', () => {
@@ -25,81 +23,17 @@ describe('Api', () => {
sendSpy.mockRestore();
});
describe('constructor', () => {
it('requires a provider with a send method', () => {
expect(
() => new Api({})
).toThrow(/Expected Provider/);
});
it('sets up the chain interface', () => {
expect(api.chain).toBeDefined();
});
it('sets up the state interface', () => {
expect(api.state).toBeDefined();
});
it('requires a provider with a send method', () => {
expect(
() => new Api({})
).toThrow(/Expected Provider/);
});
describe('_createInterface', () => {
let container;
it('sets up the chain interface', () => {
expect(api.chain).toBeDefined();
});
beforeEach(() => {
container = api._createInterface({
test: {
methods: {
blah: {
inputs: [
{ name: 'foo', type: 'Address' }
],
output: { type: 'Address' }
},
bleh: {
inputs: [],
output: { type: 'Address' }
}
}
}
}, 'test');
});
describe('method expansion', () => {
it('adds the specified methods to the interface', () => {
expect(Object.keys(container)).toEqual(['blah', 'bleh']);
});
it('had function calls for the attached methods', () => {
expect(isFunction(container.blah)).toEqual(true);
expect(isFunction(container.bleh)).toEqual(true);
});
});
describe('calling', () => {
it('wraps errors with the call signature', () => {
return container
.blah()
.catch((error) => {
expect(error.message).toMatch(/test_blah \(foo: Address\): Address/);
});
});
it('checks for mismatched parameters', () => {
return container
.bleh(1)
.catch((error) => {
expect(error.message).toMatch(/0 params expected, found 1 instead/);
});
});
it('calls the provider with the correct parameters', () => {
return container
.blah('0x123')
.then(() => {
expect(provider.send).toHaveBeenCalledWith('test_blah', [
'0x0123'
]);
});
});
});
it('sets up the state interface', () => {
expect(api.state).toBeDefined();
});
});
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { InterfaceDefinition } from '@polkadot/api-jsonrpc/types';
import type { ProviderInterface } from '@polkadot/api-provider/types';
import type { ApiInterface$Section } from '../types';
const { formatInputs, formatOutput } = require('@polkadot/api-format');
const assert = require('@polkadot/util/assert');
const ExtError = require('@polkadot/util/ext/error');
const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature');
module.exports = function createInterface (provider: ProviderInterface, definition: InterfaceDefinition, section: string): ApiInterface$Section {
return Object
.keys(definition.methods)
.reduce((container, method: string) => {
const { inputs, output } = definition.methods[method];
const rpcName = `${section}_${method}`;
container[method] = async (..._params: Array<mixed>): Promise<mixed> => {
try {
assert(inputs.length === _params.length, `${inputs.length} params expected, found ${_params.length} instead`);
const params = formatInputs(inputs, _params);
const result = await provider.send(rpcName, params);
return formatOutput(output, result);
} catch (error) {
throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code);
}
};
return container;
}, ({}: $Shape<ApiInterface$Section>));
};
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const isFunction = require('@polkadot/util/is/function');
const createInterface = require('./interface');
describe('createInterface', () => {
let container;
let provider;
beforeEach(() => {
const definition = {
methods: {
blah: {
inputs: [
{ name: 'foo', type: 'Address' }
],
output: { type: 'Address' }
},
bleh: {
inputs: [],
output: { type: 'Address' }
}
}
};
provider = {
send: jest.fn((method, params) => {
return Promise.resolve(params[0]);
})
};
container = createInterface(provider, definition, 'test');
});
describe('method expansion', () => {
it('adds the specified methods to the interface', () => {
expect(Object.keys(container)).toEqual(['blah', 'bleh']);
});
it('had function calls for the attached methods', () => {
expect(isFunction(container.blah)).toEqual(true);
expect(isFunction(container.bleh)).toEqual(true);
});
});
describe('calling', () => {
it('wraps errors with the call signature', () => {
return container
.blah()
.catch((error) => {
expect(error.message).toMatch(/test_blah \(foo: Address\): Address/);
});
});
it('checks for mismatched parameters', () => {
return container
.bleh(1)
.catch((error) => {
expect(error.message).toMatch(/0 params expected, found 1 instead/);
});
});
it('calls the provider with the correct parameters', () => {
return container
.blah('0x123')
.then(() => {
expect(provider.send).toHaveBeenCalledWith('test_blah', [
'0x0123'
]);
});
});
});
});