> Am 13.12.2017 um 11:04 schrieb Sven Van Caekenberghe <s...@stfx.eu>: > > > >>> On 13 Dec 2017, at 10:54, Norbert Hartl <norb...@hartl.name> wrote: >>> >>> >>> Am 13.12.2017 um 10:18 schrieb Sven Van Caekenberghe <s...@stfx.eu>: >>> >>> >>> >>>> On 13 Dec 2017, at 10:14, Norbert Hartl <norb...@hartl.name> wrote: >>>> >>>> To make your core a little bit more reliable you should not catch the >>>> general error but a NeoJSONParseError. And you need to guard the >>>> dictionary access. There is no guarantee you get something back that >>>> inlcudes key success and message. >>> >>> Yes, indeed. >>> >>> Also, a better REST API (not something you can change) would not return 200 >>> OK with an error in the payload, but would return a 404 Not Found with a >>> proper error object as payload. >>> >> I must say that the latter is not a good advize. All HTTP status codes refer >> to the resource that is specified in the uri. REST is resource based but GET >> and POST are exceptions beacuse they can address processing entities. It >> means that the result of the operation is not the entity in the uri. >> Returning a 404 would mean that the >> >> https://bittrex.com/api/v1.1/public/getticker >> >> resource is not available but that is not true and can lead to unwanted >> behaviour, e.g. that a http stack caches the error and does not try to >> access that resource again. So the proper status code depends on the >> definition of the interface. If it is considered to always return an object >> then the status code needs to be 400 because the specification of the client >> was invalid. On the other hand you can just return a 200 with an empty >> result if the search result is optional. >> >> my 2 cents, > > Well, yes, you're right. I was too quick and assumed the resource was > properly named. > > That was another remark. The interface does not properly refer to a resource, > it is still too procedural, IMHO. > > I would write it as > > https://bittrex.com/api/v1.1/public/tickers/LTC > > A process interface should only be used for, duh, processes that can be > identified as such, like a trade that then gets its own unique URI that can > be queried for state and so on. > > REST interface design is a subject we can discuss endlessly, no doubt. > No doubt! But with you I might enjoy it 😉 Nevertheless I think we don‘t want to live without RPC and that is hard to map on REST.
Norbert >> Norbert >> >>> FWIW, there are a couple of more sophisticated examples, like in >>> NeoJSONMappingTests and NeoJSONExamplesTests, with comments that do various >>> special cases. >>> >>>> Norbert >>>> >>>>> Am 13.12.2017 um 09:54 schrieb Ben Coman <b...@openinworld.com>: >>>>> >>>>> hi Sven, >>>>> >>>>>> On 13 Dec 2017, at 07:59, Ben Coman <b...@openinworld.com> wrote: >>>>>> >>>>>> >>>>>> With... >>>>>> Object subclass: #BittrexResponse >>>>>> instanceVariableNames: 'success message result' >>>>>> classVariableNames: '' >>>>>> package: 'Bittrex' >>>>>> >>>>>> Object subclass: #BittrexMarketSummary >>>>>> instanceVariableNames: 'MarketName High Low Volume Last >>>>>> BaseVolume TimeStamp Bid Ask OpenBuyOrders >>>>>> OpenSellOrders PrevDay Created DisplayMarketName' >>>>>> classVariableNames: '' >>>>>> package: 'Bittrex' >>>>>> >>>>>> this code works great when the response holds good data... >>>>>> ZnClient new >>>>>> url: >>>>>> 'https://bittrex.com/api/v1.1/public/getmarketSummary?market=BTC-LTC'; >>>>>> enforceHttpSuccess: true; >>>>>> accept: ZnMimeType applicationJson; >>>>>> contentReader: [ :entity | |reader| >>>>>> reader := (NeoJSONReader on: entity readStream). >>>>>> reader for: BittrexResponse do: [:m| >>>>>> m mapInstVar: #success. >>>>>> m mapInstVar: #message. >>>>>> (m mapInstVar: #result) valueSchema: #ResultArray]. >>>>>> reader for: #ResultArray customDo: [ :mapping | >>>>>> mapping listOfElementSchema: BittrexMarketSummary ]. >>>>>> reader mapInstVarsFor: BittrexMarketSummary. >>>>>> reader nextAs: BittrexResponse ]; >>>>>> get. >>>>>> >>>>>> i.e. a raw response looking like this.... >>>>>> (ZnClient new >>>>>> url: >>>>>> 'https://bittrex.com/api/v1.1/public/getmarketsummary?market=BTC-LTC'; >>>>>> get) inspect. >>>>>> ==> >>>>>> "'{""success"":true,""message"":"",""result"":[{""MarketName"":""BTC-LTC"",""High"":0.01982450,""Low"":0.01285257,""Volume"":1436429.81313360,""Last"":0.01842000,""BaseVolume"":24841.17217724,""TimeStamp"":""2017-12-13T05:56:25.937"",""Bid"":0.01840001,""Ask"":0.01842000,""OpenBuyOrders"":10140,""OpenSellOrders"":6306,""PrevDay"":0.01439800,""Created"":""2014-02-13T00:00:00""}]}'" >>>>>> >>>>>> >>>>>> But for bad response looking like this... >>>>>> (ZnClient new >>>>>> url: >>>>>> 'https://bittrex.com/api/v1.1/public/getmarketsummary?market=INVALID'; >>>>>> get) inspect. >>>>>> ==> {"success":false,"message":"INVALID_MARKET","result":null} >>>>>> >>>>>> the JSON handling code fails deep in the call stack with an error >>>>>> "NeoJSONParseError: [ expected" >>>>>> which is not so friendly for users of the Bittrex library. >>>>>> >>>>>> What are the different/recommended approaches with Zinc >>>>>> for catching JSON errors such that I can pass "message" >>>>>> as a higher level Error up the stack to the Bittrex user. >>>>>> >>>>>> cheers -ben >>>>> >>>>> >>>>> On 13 December 2017 at 15:37, Sven Van Caekenberghe <s...@stfx.eu> wrote: >>>>> BTW, this is no about Zinc, but about NeoJSON. >>>>> >>>>> This is what I meant with variability that is hard to capture with a >>>>> simple static type schema. >>>>> >>>>> I have no time to try myself right now, but a custom mapping for ivar >>>>> result (as in a block) might be able to see the difference and act >>>>> accordingly. >>>>> >>>>> >>>>> okay. So I played around tracing this through the debugger and for >>>>> anyone else >>>>> with a similar need later, I ended up with the following... >>>>> >>>>> response := (ZnClient new >>>>> url: 'https://bittrex.com/api/v1.1/public/getticker?market=INVALID'; >>>>> enforceHttpSuccess: true; >>>>> accept: ZnMimeType applicationJson; >>>>> contentReader: >>>>> [ :entity | >>>>> [ |reader| >>>>> reader := (NeoJSONReader on: entity readStream). >>>>> reader for: BittrexResponse do: >>>>> [:m| >>>>> m mapInstVar: #success. >>>>> m mapInstVar: #message. >>>>> (m mapInstVar: #result) valueSchema: BittrexTicker >>>>> ]. >>>>> reader mapInstVarsFor: BittrexTicker. >>>>> reader nextAs: BittrexResponse >>>>> ] on: Error do: >>>>> [ :err | |json| >>>>> json := NeoJSONReader fromString: entity contents. >>>>> (json at: 'success') >>>>> ifFalse: [ self error: (json at: 'message') ] >>>>> ifTrue: [ self error: 'UKNOWN ERROR' ] >>>>> ] >>>>> ]) get. >>>>> >>>>> >>>>> for which I get a nice pre-debug window titled "Error: INVALID_MARKET" >>>>> >>>>> cheers -ben