Nested JSON REST

> I guess part of what I’m interested in are patterns for hooking
> NeoJSON up to parse a REST response into objects to build a wrapper
> around a REST service. I see a chapter in Enterprise Pharo, which I’ll
> get to that soon.  Perhaps I was premature asking before reading that,
> but its good to have a few paths to explore.

Here is a recent example http://forum.world.st/Another-example-of-invoking-a-REST-JSON-web-service-resolving-User-Agent-strings-tt5017489.html

Thanks Sven.  That helped a lot.   I’d like to report success.
It may be useful to others to see how to progressively build up to parsing a Nested JSON REST
1. First parse the JSON into simple Dictionaries…
(ZnClient new
    enforceHttpSuccess: true;
    accept: ZnMimeType applicationJson;
    contentReader: [ :entity | NeoJSONReader fromString: entity contents ];
get) inspect.
==>Dictionary(
      ‘success’ ==> true
      ‘message’ ==> ”
      ‘result ‘ ==> an Array(a Dictionary(‘BaseCurrency’->’BTC’ ‘BaseCurrencyLong’->’Bitcoin’)
… a Dictionary(‘BaseCurrency’->’ETH’ ‘BaseCurrencyLong’->’Ethereum’)
2. Then parse the first level response into a real object…
Object subclass: #BittrexResponse
    instanceVariableNames: ‘success message result’
    classVariableNames: ”
    package: ‘Bittrex’
(ZnClient new
   enforceHttpSuccess: true;
   accept: ZnMimeType applicationJson;
   contentReader: [ :entity |
       (NeoJSONReader on: entity readStream)
mapInstVarsFor: BittrexResponse ;
         nextAs: BittrexResponse ];
      get) inspect.
==>BittrexResponse
      success => true
      message => ”
      result => an Array(a Dictionary(‘BaseCurrency’->’BTC’ ‘BaseCurrencyLong’->’Bitcoin’)
… a Dictionary(‘BaseCurrency’->’ETH’ ‘BaseCurrencyLong’->’Ethereum’)
Or alternatively…
(ZnClient new
   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 ].
    reader nextAs: BittrexResponse ];
   get) inspect.
==>BittrexResponse
      success => true
      message => ”
      result => an Array(a Dictionary(‘BaseCurrency’->’BTC’ ‘BaseCurrencyLong’->’Bitcoin’)
… a Dictionary(‘BaseCurrency’->’ETH’ ‘BaseCurrencyLong’->’Ethereum’)
3. Finally parse into real objects the nested level holding the data you really want…
Object subclass: #Market
    instanceVariableNames: ‘MarketCurrency BaseCurrency MarketCurrencyLong BaseCurrencyLong MinTradeSize MarketName IsActive Created Notice IsSponsored LogoUrl’
   classVariableNames: ”
   package: ‘Bittrex’
(ZnClient new
   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: #ArrayOfMarkets].
           reader for: #ArrayOfMarkets customDo: [ :mapping | mapping listOfElementSchema: Market ].
reader mapInstVarsFor: Market.
      reader nextAs: BittrexResponse ];
   get) inspect.

==>BittrexResponse
      success => true
      message => ”
      result => an Array(a Market(LTC) a Market(DOGE) a Market(VTC) a Market(PPC) a Market(FTC) a Market(RDD)
… Market(POWR) a Market(BTG) a Market(BTG) a Market(BTG) a Market(ADA) a Market(ENG) a Market(ENG))
WhooHoo!
A couple of things remaining:
* The instance variables of Market currently start with an upper-case to match the JSON fields.
  Lower-casing the first letter breaks things.
  What strategies can be used to conform here to Smalltalk conventions?
  Or is it easy enough to live with it?
* In various posts I’ve seen mention of a class-side method #neoJsonMapping:
   but there is no explanation of this in the Enterprise Book.
   How might #neoJsonMapping: come into the picture for my use case above?
cheers -ben
Advertisements
%d bloggers like this: