diff options
author | Brandon Millman <brandon@0xproject.com> | 2018-01-10 06:38:33 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-10 06:38:33 +0800 |
commit | 40c7ee63557b1795340c315eb9fab1dcfe092bed (patch) | |
tree | 864f5b616e9efb38b0282ab829871f794df0b0cd | |
parent | 7a56e83fa3ca02d796deba3359da480834a9f6ea (diff) | |
parent | eb760aa33f0e158b3d26058aa1e9906a1f400a14 (diff) | |
download | dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.tar dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.tar.gz dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.tar.bz2 dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.tar.lz dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.tar.xz dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.tar.zst dexon-sol-tools-40c7ee63557b1795340c315eb9fab1dcfe092bed.zip |
Merge pull request #311 from 0xProject/fix/httpClientJsonParsing
Merge connect json parsing refactor into development
-rw-r--r-- | packages/connect/src/http_client.ts | 36 | ||||
-rw-r--r-- | packages/connect/src/utils/orderbook_channel_message_parser.ts (renamed from packages/connect/src/utils/orderbook_channel_message_parsers.ts) | 18 | ||||
-rw-r--r-- | packages/connect/src/utils/relayer_response_json_parsers.ts | 37 | ||||
-rw-r--r-- | packages/connect/src/utils/type_converters.ts | 22 | ||||
-rw-r--r-- | packages/connect/src/ws_orderbook_channel.ts | 4 | ||||
-rw-r--r-- | packages/connect/test/orderbook_channel_message_parsers_test.ts | 21 |
6 files changed, 84 insertions, 54 deletions
diff --git a/packages/connect/src/http_client.ts b/packages/connect/src/http_client.ts index dcaf5d9a9..5604a9607 100644 --- a/packages/connect/src/http_client.ts +++ b/packages/connect/src/http_client.ts @@ -18,7 +18,7 @@ import { TokenPairsItem, TokenPairsRequest, } from './types'; -import { typeConverters } from './utils/type_converters'; +import { relayerResponseJsonParsers } from './utils/relayer_response_json_parsers'; /** * This class includes all the functionality related to interacting with a set of HTTP endpoints @@ -48,16 +48,8 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema); - _.each(tokenPairs, (tokenPair: object) => { - typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ - 'tokenA.minAmount', - 'tokenA.maxAmount', - 'tokenB.minAmount', - 'tokenB.maxAmount', - ]); - }); + const responseJson = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); + const tokenPairs = relayerResponseJsonParsers.parseTokenPairsJson(responseJson); return tokenPairs; } /** @@ -72,9 +64,8 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const orders = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); - _.each(orders, (order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order)); + const responseJson = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts); + const orders = relayerResponseJsonParsers.parseOrdersJson(responseJson); return orders; } /** @@ -84,9 +75,8 @@ export class HttpClient implements Client { */ public async getOrderAsync(orderHash: string): Promise<SignedOrder> { assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); - const order = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get); - assert.doesConformToSchema('order', order, schemas.signedOrderSchema); - typeConverters.convertOrderStringFieldsToBigNumber(order); + const responseJson = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get); + const order = relayerResponseJsonParsers.parseOrderJson(responseJson); return order; } /** @@ -99,10 +89,9 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const orderBook = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('orderBook', orderBook, schemas.relayerApiOrderBookResponseSchema); - typeConverters.convertOrderbookStringFieldsToBigNumber(orderBook); - return orderBook; + const responseJson = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts); + const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(responseJson); + return orderbook; } /** * Retrieve fee information from the API @@ -114,9 +103,8 @@ export class HttpClient implements Client { const requestOpts = { payload: request, }; - const fees = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts); - assert.doesConformToSchema('fees', fees, schemas.relayerApiFeesResponseSchema); - typeConverters.convertStringsFieldsToBigNumbers(fees, ['makerFee', 'takerFee']); + const responseJson = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts); + const fees = relayerResponseJsonParsers.parseFeesResponseJson(responseJson); return fees; } /** diff --git a/packages/connect/src/utils/orderbook_channel_message_parsers.ts b/packages/connect/src/utils/orderbook_channel_message_parser.ts index a4f22dc4b..9a9ca8901 100644 --- a/packages/connect/src/utils/orderbook_channel_message_parsers.ts +++ b/packages/connect/src/utils/orderbook_channel_message_parser.ts @@ -4,10 +4,10 @@ import * as _ from 'lodash'; import { OrderbookChannelMessage, OrderbookChannelMessageTypes } from '../types'; -import { typeConverters } from './type_converters'; +import { relayerResponseJsonParsers } from './relayer_response_json_parsers'; -export const orderbookChannelMessageParsers = { - parser(utf8Data: string): OrderbookChannelMessage { +export const orderbookChannelMessageParser = { + parse(utf8Data: string): OrderbookChannelMessage { const messageObj = JSON.parse(utf8Data); const type: string = _.get(messageObj, 'type'); assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`); @@ -15,15 +15,15 @@ export const orderbookChannelMessageParsers = { switch (type) { case OrderbookChannelMessageTypes.Snapshot: { assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema); - const orderbook = messageObj.payload; - typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook); - return messageObj; + const orderbookJson = messageObj.payload; + const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(orderbookJson); + return _.assign(messageObj, { payload: orderbook }); } case OrderbookChannelMessageTypes.Update: { assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema); - const order = messageObj.payload; - typeConverters.convertOrderStringFieldsToBigNumber(order); - return messageObj; + const orderJson = messageObj.payload; + const order = relayerResponseJsonParsers.parseOrderJson(orderJson); + return _.assign(messageObj, { payload: order }); } default: { return { diff --git a/packages/connect/src/utils/relayer_response_json_parsers.ts b/packages/connect/src/utils/relayer_response_json_parsers.ts new file mode 100644 index 000000000..668461bf4 --- /dev/null +++ b/packages/connect/src/utils/relayer_response_json_parsers.ts @@ -0,0 +1,37 @@ +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; +import * as _ from 'lodash'; + +import { FeesResponse, OrderbookResponse, SignedOrder, TokenPairsItem } from '../types'; + +import { typeConverters } from './type_converters'; + +export const relayerResponseJsonParsers = { + parseTokenPairsJson(json: any): TokenPairsItem[] { + assert.doesConformToSchema('tokenPairs', json, schemas.relayerApiTokenPairsResponseSchema); + return json.map((tokenPair: any) => { + return typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ + 'tokenA.minAmount', + 'tokenA.maxAmount', + 'tokenB.minAmount', + 'tokenB.maxAmount', + ]); + }); + }, + parseOrdersJson(json: any): SignedOrder[] { + assert.doesConformToSchema('orders', json, schemas.signedOrdersSchema); + return json.map((order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order)); + }, + parseOrderJson(json: any): SignedOrder { + assert.doesConformToSchema('order', json, schemas.signedOrderSchema); + return typeConverters.convertOrderStringFieldsToBigNumber(json); + }, + parseOrderbookResponseJson(json: any): OrderbookResponse { + assert.doesConformToSchema('orderBook', json, schemas.relayerApiOrderBookResponseSchema); + return typeConverters.convertOrderbookStringFieldsToBigNumber(json); + }, + parseFeesResponseJson(json: any): FeesResponse { + assert.doesConformToSchema('fees', json, schemas.relayerApiFeesResponseSchema); + return typeConverters.convertStringsFieldsToBigNumbers(json, ['makerFee', 'takerFee']); + }, +}; diff --git a/packages/connect/src/utils/type_converters.ts b/packages/connect/src/utils/type_converters.ts index ccbc40677..ad27e0b97 100644 --- a/packages/connect/src/utils/type_converters.ts +++ b/packages/connect/src/utils/type_converters.ts @@ -1,15 +1,17 @@ import { BigNumber } from 'bignumber.js'; import * as _ from 'lodash'; -// TODO: convert all of these to non-mutating, pure functions export const typeConverters = { - convertOrderbookStringFieldsToBigNumber(orderbook: object): void { - _.each(orderbook, (orders: object[]) => { - _.each(orders, (order: object) => this.convertOrderStringFieldsToBigNumber(order)); - }); + convertOrderbookStringFieldsToBigNumber(orderbook: any): any { + const bids = _.get(orderbook, 'bids', []); + const asks = _.get(orderbook, 'asks', []); + return { + bids: bids.map((order: any) => this.convertOrderStringFieldsToBigNumber(order)), + asks: asks.map((order: any) => this.convertOrderStringFieldsToBigNumber(order)), + }; }, - convertOrderStringFieldsToBigNumber(order: object): void { - this.convertStringsFieldsToBigNumbers(order, [ + convertOrderStringFieldsToBigNumber(order: any): any { + return this.convertStringsFieldsToBigNumbers(order, [ 'makerTokenAmount', 'takerTokenAmount', 'makerFee', @@ -18,9 +20,11 @@ export const typeConverters = { 'salt', ]); }, - convertStringsFieldsToBigNumbers(obj: object, fields: string[]): void { + convertStringsFieldsToBigNumbers(obj: any, fields: string[]): any { + const result = _.assign({}, obj); _.each(fields, field => { - _.update(obj, field, (value: string) => new BigNumber(value)); + _.update(result, field, (value: string) => new BigNumber(value)); }); + return result; }, }; diff --git a/packages/connect/src/ws_orderbook_channel.ts b/packages/connect/src/ws_orderbook_channel.ts index 399f97319..822a022f4 100644 --- a/packages/connect/src/ws_orderbook_channel.ts +++ b/packages/connect/src/ws_orderbook_channel.ts @@ -11,7 +11,7 @@ import { WebsocketClientEventType, WebsocketConnectionEventType, } from './types'; -import { orderbookChannelMessageParsers } from './utils/orderbook_channel_message_parsers'; +import { orderbookChannelMessageParser } from './utils/orderbook_channel_message_parser'; /** * This class includes all the functionality related to interacting with a websocket endpoint @@ -104,7 +104,7 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { if (!_.isUndefined(message.utf8Data)) { try { const utf8Data = message.utf8Data; - const parserResult = orderbookChannelMessageParsers.parser(utf8Data); + const parserResult = orderbookChannelMessageParser.parse(utf8Data); if (parserResult.requestId === requestId) { switch (parserResult.type) { case OrderbookChannelMessageTypes.Snapshot: { diff --git a/packages/connect/test/orderbook_channel_message_parsers_test.ts b/packages/connect/test/orderbook_channel_message_parsers_test.ts index e6cc05fed..3e1f44384 100644 --- a/packages/connect/test/orderbook_channel_message_parsers_test.ts +++ b/packages/connect/test/orderbook_channel_message_parsers_test.ts @@ -2,7 +2,7 @@ import * as chai from 'chai'; import * as dirtyChai from 'dirty-chai'; import 'mocha'; -import { orderbookChannelMessageParsers } from '../src/utils/orderbook_channel_message_parsers'; +import { orderbookChannelMessageParser } from '../src/utils/orderbook_channel_message_parser'; import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook'; @@ -20,20 +20,20 @@ chai.config.includeStack = true; chai.use(dirtyChai); const expect = chai.expect; -describe('orderbookChannelMessageParsers', () => { +describe('orderbookChannelMessageParser', () => { describe('#parser', () => { it('parses snapshot messages', () => { - const snapshotMessage = orderbookChannelMessageParsers.parser(snapshotOrderbookChannelMessage); + const snapshotMessage = orderbookChannelMessageParser.parse(snapshotOrderbookChannelMessage); expect(snapshotMessage.type).to.be.equal('snapshot'); expect(snapshotMessage.payload).to.be.deep.equal(orderbookResponse); }); it('parses update messages', () => { - const updateMessage = orderbookChannelMessageParsers.parser(updateOrderbookChannelMessage); + const updateMessage = orderbookChannelMessageParser.parse(updateOrderbookChannelMessage); expect(updateMessage.type).to.be.equal('update'); expect(updateMessage.payload).to.be.deep.equal(orderResponse); }); it('returns unknown message for messages with unsupported types', () => { - const unknownMessage = orderbookChannelMessageParsers.parser(unknownOrderbookChannelMessage); + const unknownMessage = orderbookChannelMessageParser.parse(unknownOrderbookChannelMessage); expect(unknownMessage.type).to.be.equal('unknown'); expect(unknownMessage.payload).to.be.undefined(); }); @@ -43,7 +43,7 @@ describe('orderbookChannelMessageParsers', () => { "requestId": 1, "payload": {} }`; - const badCall = () => orderbookChannelMessageParsers.parser(typelessMessage); + const badCall = () => orderbookChannelMessageParser.parse(typelessMessage); expect(badCall).throws(`Message is missing a type parameter: ${typelessMessage}`); }); it('throws when type is not a string', () => { @@ -53,22 +53,23 @@ describe('orderbookChannelMessageParsers', () => { "requestId": 1, "payload": {} }`; - const badCall = () => orderbookChannelMessageParsers.parser(messageWithBadType); + const badCall = () => orderbookChannelMessageParser.parse(messageWithBadType); expect(badCall).throws('Expected type to be of type string, encountered: 1'); }); it('throws when snapshot message has malformed payload', () => { - const badCall = () => orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage); + const badCall = () => orderbookChannelMessageParser.parse(malformedSnapshotOrderbookChannelMessage); + // tslint:disable-next-line:max-line-length const errMsg = 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"'; expect(badCall).throws(errMsg); }); it('throws when update message has malformed payload', () => { - const badCall = () => orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage); + const badCall = () => orderbookChannelMessageParser.parse(malformedUpdateOrderbookChannelMessage); expect(badCall).throws(/^Expected message to conform to schema/); }); it('throws when input message is not valid JSON', () => { const nonJsonString = 'h93b{sdfs9fsd f'; - const badCall = () => orderbookChannelMessageParsers.parser(nonJsonString); + const badCall = () => orderbookChannelMessageParser.parse(nonJsonString); expect(badCall).throws('Unexpected token h in JSON at position 0'); }); }); |