REST client hints

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

REST client hints

Ben Coman
I'm just about to write my first client interface to a REST service.
In some respects I understand this is as simple as doing GET responses
using Zinc,
but I'm inquiring about tutorials or libraries that might help.  Most
of the stuff turned up by searches is about server-side of REST.

cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

EstebanLM
Hi,


On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:

I'm just about to write my first client interface to a REST service.
In some respects I understand this is as simple as doing GET responses
using Zinc,

yes, is about that.
GET/POST/PUT/DELETE

all have sense. 

but I'm inquiring about tutorials or libraries that might help.  Most
of the stuff turned up by searches is about server-side of REST.

I’m currently playing with my latest fun project pharo-mastodon, http://github.com/estebanlm/pharo-mastodon (the long term project is “getting out twitter” :P). 
It is actually a rest api… and since is very young, is not complicated at all, so you can take it as an example (probably of "things not to do”, but well… ;) )

Esteban



cheers -ben


Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Peter Uhnák
With ZnClient you can also dynamically extend paths (#addPath:), specify parameters (#formAt:put:, #queryAt:put:), provide raw #contents:, etc.

But what would be nice is to convert the responses to some domain objects. So e.g. when I query trello for all lists, I would like to get as a result not json, but List instances, where if I asked for cards, it would query the cards from the server.

I recommend also looking at this project by Richard Prinz https://www.min.at/prinz/?x=entry:entry150318-104537 which basically discovers the API and generates a nice implementation for it. Then you use the generated API instead of worrying about constructing HTTP requests.

Peter

On Tue, Dec 5, 2017 at 12:59 PM, Esteban Lorenzano <[hidden email]> wrote:
Hi,


On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:

I'm just about to write my first client interface to a REST service.
In some respects I understand this is as simple as doing GET responses
using Zinc,

yes, is about that.
GET/POST/PUT/DELETE

all have sense. 

but I'm inquiring about tutorials or libraries that might help.  Most
of the stuff turned up by searches is about server-side of REST.

I’m currently playing with my latest fun project pharo-mastodon, http://github.com/estebanlm/pharo-mastodon (the long term project is “getting out twitter” :P). 
It is actually a rest api… and since is very young, is not complicated at all, so you can take it as an example (probably of "things not to do”, but well… ;) )

Esteban



cheers -ben



Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Sven Van Caekenberghe-2
In reply to this post by Ben Coman
Ben,

> On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:
>
> I'm just about to write my first client interface to a REST service.
> In some respects I understand this is as simple as doing GET responses
> using Zinc,
> but I'm inquiring about tutorials or libraries that might help.  Most
> of the stuff turned up by searches is about server-side of REST.
>
> cheers -ben

I am not sure what you are looking for, but it is not difficult to do. ZnClient is your go to class.

The Enterprise Pharo book chapters about HTTP client & server are starting points (in particular section 11 of the former, and very specifically 11.3).

HTH,

Sven



Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Ben Coman
@esteban, thx, I'll take a look at mastodon.

@peter, I remember playing with the Google API when Richard published
that.  thx for the reminder.

@sven, I started reading Enterprise Pharo a couple of hours ago.
I don't quite get your section references. I presume you
don't mean "chapter 11 Persisting Objects with Voyage, 11.3 Enhancing Storage"
That seems off topic. And "chapter 4  Zinc HTTP: The Client Side, 4.11 Headers"
doesn't have a sub-part "3".

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.

btw, here is the concrete case...
https://bittrex.com/home/api

cheers -ben

On 5 December 2017 at 20:06, Sven Van Caekenberghe <[hidden email]> wrote:

> Ben,
>
>> On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:
>>
>> I'm just about to write my first client interface to a REST service.
>> In some respects I understand this is as simple as doing GET responses
>> using Zinc,
>> but I'm inquiring about tutorials or libraries that might help.  Most
>> of the stuff turned up by searches is about server-side of REST.
>>
>> cheers -ben
>
> I am not sure what you are looking for, but it is not difficult to do. ZnClient is your go to class.
>
> The Enterprise Pharo book chapters about HTTP client & server are starting points (in particular section 11 of the former, and very specifically 11.3).
>
> HTH,
>
> Sven
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Miguel Moquillon
In reply to this post by Peter Uhnák

There is also the OpenAPI specification dedicated to define a REST API and from which a skeleton of an implementation can be generated. It should be then also possible to generate the skeleton of a client for such an API.

Swagger provides tooling to the OpenAPI specification for several programming languages. Unfortunately, it seams there is no implementation for Smalltalk.

Miguel


Le 05/12/2017 à 13:05, Peter Uhnák a écrit :
With ZnClient you can also dynamically extend paths (#addPath:), specify parameters (#formAt:put:, #queryAt:put:), provide raw #contents:, etc.

But what would be nice is to convert the responses to some domain objects. So e.g. when I query trello for all lists, I would like to get as a result not json, but List instances, where if I asked for cards, it would query the cards from the server.

I recommend also looking at this project by Richard Prinz https://www.min.at/prinz/?x=entry:entry150318-104537 which basically discovers the API and generates a nice implementation for it. Then you use the generated API instead of worrying about constructing HTTP requests.

Peter

On Tue, Dec 5, 2017 at 12:59 PM, Esteban Lorenzano <[hidden email]> wrote:
Hi,


On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:

I'm just about to write my first client interface to a REST service.
In some respects I understand this is as simple as doing GET responses
using Zinc,

yes, is about that.
GET/POST/PUT/DELETE

all have sense. 

but I'm inquiring about tutorials or libraries that might help.  Most
of the stuff turned up by searches is about server-side of REST.

I’m currently playing with my latest fun project pharo-mastodon, http://github.com/estebanlm/pharo-mastodon (the long term project is “getting out twitter” :P). 
It is actually a rest api… and since is very young, is not complicated at all, so you can take it as an example (probably of "things not to do”, but well… ;) )

Esteban



cheers -ben




Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Sven Van Caekenberghe-2
In reply to this post by Ben Coman


> On 5 Dec 2017, at 13:33, Ben Coman <[hidden email]> wrote:
>
> @esteban, thx, I'll take a look at mastodon.
>
> @peter, I remember playing with the Google API when Richard published
> that.  thx for the reminder.
>
> @sven, I started reading Enterprise Pharo a couple of hours ago.
> I don't quite get your section references. I presume you
> don't mean "chapter 11 Persisting Objects with Voyage, 11.3 Enhancing Storage"
> That seems off topic. And "chapter 4  Zinc HTTP: The Client Side, 4.11 Headers"
> doesn't have a sub-part "3".

I meant 11.3 in this page https://ci.inria.fr/pharo-contribution/job/EnterprisePharoBook/lastSuccessfulBuild/artifact/book-result/Zinc-HTTP-Server/Zinc-HTTP-Server.html a section called 11.3. A Zinc Client.

> 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

> btw, here is the concrete case...
> https://bittrex.com/home/api
>
> cheers -ben
>
> On 5 December 2017 at 20:06, Sven Van Caekenberghe <[hidden email]> wrote:
>> Ben,
>>
>>> On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:
>>>
>>> I'm just about to write my first client interface to a REST service.
>>> In some respects I understand this is as simple as doing GET responses
>>> using Zinc,
>>> but I'm inquiring about tutorials or libraries that might help.  Most
>>> of the stuff turned up by searches is about server-side of REST.
>>>
>>> cheers -ben
>>
>> I am not sure what you are looking for, but it is not difficult to do. ZnClient is your go to class.
>>
>> The Enterprise Pharo book chapters about HTTP client & server are starting points (in particular section 11 of the former, and very specifically 11.3).
>>
>> HTH,
>>
>> Sven
>>
>>
>>
>


Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Ben Coman
On 5 December 2017 at 20:44, Sven Van Caekenberghe <[hidden email]> wrote:

>
>
>> On 5 Dec 2017, at 13:33, Ben Coman <[hidden email]> wrote:
>>
>> @esteban, thx, I'll take a look at mastodon.
>>
>> @peter, I remember playing with the Google API when Richard published
>> that.  thx for the reminder.
>>
>> @sven, I started reading Enterprise Pharo a couple of hours ago.
>> I don't quite get your section references. I presume you
>> don't mean "chapter 11 Persisting Objects with Voyage, 11.3 Enhancing Storage"
>> That seems off topic. And "chapter 4  Zinc HTTP: The Client Side, 4.11 Headers"
>> doesn't have a sub-part "3".
>
> I meant 11.3 in this page https://ci.inria.fr/pharo-contribution/job/EnterprisePharoBook/lastSuccessfulBuild/artifact/book-result/Zinc-HTTP-Server/Zinc-HTTP-Server.html a section called 11.3. A Zinc Client.
>
>
>> 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
>

thx. those are both the examples I was seeking.
btw, note the different numbering here...
http://files.pharo.org/books-pdfs/entreprise-pharo/2016-10-06-EnterprisePharo.pdf
"A Zinc client" is in section 5.11 with part "3" unnumbered

cheers -ben

>> btw, here is the concrete case...
>> https://bittrex.com/home/api
>>
>> cheers -ben
>>
>> On 5 December 2017 at 20:06, Sven Van Caekenberghe <[hidden email]> wrote:
>>> Ben,
>>>
>>>> On 5 Dec 2017, at 12:15, Ben Coman <[hidden email]> wrote:
>>>>
>>>> I'm just about to write my first client interface to a REST service.
>>>> In some respects I understand this is as simple as doing GET responses
>>>> using Zinc,
>>>> but I'm inquiring about tutorials or libraries that might help.  Most
>>>> of the stuff turned up by searches is about server-side of REST.
>>>>
>>>> cheers -ben
>>>
>>> I am not sure what you are looking for, but it is not difficult to do. ZnClient is your go to class.
>>>
>>> The Enterprise Pharo book chapters about HTTP client & server are starting points (in particular section 11 of the former, and very specifically 11.3).
>>>
>>> HTH,
>>>
>>> Sven
>>>
>>>
>>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Paul DeBruicker
In reply to this post by Ben Coman
Hi Ben,


I've made a few REST Clients

http://smalltalkhub.com/#!/~pdebruic/Stripe
http://smalltalkhub.com/#!/~pdebruic/Tropo
http://smalltalkhub.com/#!/~pdebruic/SegmentIO

And the elasticsearch one but its been advanced mostly lately by Sho Yoshida
(https://github.com/newapplesho) here
https://github.com/newapplesho/elasticsearch-smalltalk

He has also made REST clients for Twilio, AWS, SendGrid, Salesforce, and
Mixpanel among others.

Norbert Hartl made one for Mandrill (Mailchimps transactional email service)
http://smalltalkhub.com/#!/~NorbertHartl/Mandrill

And Francois Stephany made one for Postmark (another transactional email
service) http://smalltalkhub.com/#!/~PharoExtras/Postmark


So those are some examples of different approaches.  


I also started/made a cross platform web client wrapper (just wraps calls to
ZnClient or WebClient on Squeak)
http://smalltalkhub.com/#!/~pdebruic/HTTPAPIClient

But IIRC I only used it in the Stripe API client.  


Hope this gives you some ideas about how to approach your own solution

Paul



Ben Coman wrote
> I'm just about to write my first client interface to a REST service.
> In some respects I understand this is as simple as doing GET responses
> using Zinc,
> but I'm inquiring about tutorials or libraries that might help.  Most
> of the stuff turned up by searches is about server-side of REST.
>
> cheers -ben





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Ben Coman
Thanks Paul. It'll be good to review some concrete implementations,
and nice to see what services other other people find useful. 
I got a momentary urge the create a Pharo Distribution or catalog entry called
something like "SamplRest" with a GUI to explore available REST data sources.
Marketing angle for Pharo would be helping less technical people get a "live" hold of
data from these sources, and then incrementally script against those live objects.
I guess a bit like SegmentIO but on your own desktop rather than through a third party.
(but I've not got the time right now)

cheers -ben

On 6 December 2017 at 02:46, Paul DeBruicker <[hidden email]> wrote:
Hi Ben,


I've made a few REST Clients

http://smalltalkhub.com/#!/~pdebruic/Stripe
http://smalltalkhub.com/#!/~pdebruic/Tropo
http://smalltalkhub.com/#!/~pdebruic/SegmentIO

And the elasticsearch one but its been advanced mostly lately by Sho Yoshida
(https://github.com/newapplesho) here
https://github.com/newapplesho/elasticsearch-smalltalk

He has also made REST clients for Twilio, AWS, SendGrid, Salesforce, and
Mixpanel among others.

Norbert Hartl made one for Mandrill (Mailchimps transactional email service)
http://smalltalkhub.com/#!/~NorbertHartl/Mandrill

And Francois Stephany made one for Postmark (another transactional email
service) http://smalltalkhub.com/#!/~PharoExtras/Postmark


So those are some examples of different approaches.


I also started/made a cross platform web client wrapper (just wraps calls to
ZnClient or WebClient on Squeak)
http://smalltalkhub.com/#!/~pdebruic/HTTPAPIClient

But IIRC I only used it in the Stripe API client.


Hope this gives you some ideas about how to approach your own solution

Paul



Ben Coman wrote
> I'm just about to write my first client interface to a REST service.
> In some respects I understand this is as simple as doing GET responses
> using Zinc,
> but I'm inquiring about tutorials or libraries that might help.  Most
> of the stuff turned up by searches is about server-side of REST.
>
> cheers -ben





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html


Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Ben Coman
In reply to this post by Sven Van Caekenberghe-2

On 5 December 2017 at 20:44, Sven Van Caekenberghe <[hidden email]> wrote:

> On 5 Dec 2017, at 13:33, Ben Coman <[hidden email]> wrote:

> @sven, I started reading Enterprise Pharo a couple of hours ago.
> I don't quite get your section references. I presume you
> don't mean "chapter 11 Persisting Objects with Voyage, 11.3 Enhancing Storage"
> That seems off topic. And "chapter 4  Zinc HTTP: The Client Side, 4.11 Headers"
> doesn't have a sub-part "3".

I meant 11.3 in this page https://ci.inria.fr/pharo-contribution/job/EnterprisePharoBook/lastSuccessfulBuild/artifact/book-result/Zinc-HTTP-Server/Zinc-HTTP-Server.html a section called 11.3. A Zinc Client.

> 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

Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Stephane Ducasse-3
Tx for your report :)

https://wordpress.com/post/pharoweekly.wordpress.com/2347

Did you look at SmartShackles? on our inria github repo. Because
Santiago is extracting information from blockchains.

On Sun, Dec 10, 2017 at 4:45 AM, Ben Coman <[hidden email]> wrote:

>
> On 5 December 2017 at 20:44, Sven Van Caekenberghe <[hidden email]> wrote:
>>
>>
>> > On 5 Dec 2017, at 13:33, Ben Coman <[hidden email]> wrote:
>>
>> > @sven, I started reading Enterprise Pharo a couple of hours ago.
>> > I don't quite get your section references. I presume you
>> > don't mean "chapter 11 Persisting Objects with Voyage, 11.3 Enhancing
>> > Storage"
>> > That seems off topic. And "chapter 4  Zinc HTTP: The Client Side, 4.11
>> > Headers"
>> > doesn't have a sub-part "3".
>>
>> I meant 11.3 in this page
>> https://ci.inria.fr/pharo-contribution/job/EnterprisePharoBook/lastSuccessfulBuild/artifact/book-result/Zinc-HTTP-Server/Zinc-HTTP-Server.html
>> a section called 11.3. A Zinc Client.
>>
>> > 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
>

Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Ben Coman


On 10 December 2017 at 15:27, Stephane Ducasse <[hidden email]> wrote:
Tx for your report :)

https://wordpress.com/post/pharoweekly.wordpress.com/2347

Did you look at SmartShackles? on our inria github repo. Because
Santiago is extracting information from blockchains.


I would hesitate to call where I'm up to right now as blockchain related.  
Its just the trading api of one exchange where the items traded happen to be bitcoins.
But I have a growing interest in blockchains, so thanks for the tip...

I didn't see anything relevant here...  https://github.com/INRIA
but with that product name I found... https://github.com/sbragagnolo/SmartShackle

cheers -ben
Reply | Threaded
Open this post in threaded view
|

Re: REST client hints

Sven Van Caekenberghe-2
In reply to this post by Ben Coman


> On 10 Dec 2017, at 04:45, Ben Coman <[hidden email]> wrote:
>
>
> On 5 December 2017 at 20:44, Sven Van Caekenberghe <[hidden email]> wrote:
>
> > On 5 Dec 2017, at 13:33, Ben Coman <[hidden email]> wrote:
>
> > @sven, I started reading Enterprise Pharo a couple of hours ago.
> > I don't quite get your section references. I presume you
> > don't mean "chapter 11 Persisting Objects with Voyage, 11.3 Enhancing Storage"
> > That seems off topic. And "chapter 4  Zinc HTTP: The Client Side, 4.11 Headers"
> > doesn't have a sub-part "3".
>
> I meant 11.3 in this page https://ci.inria.fr/pharo-contribution/job/EnterprisePharoBook/lastSuccessfulBuild/artifact/book-result/Zinc-HTTP-Server/Zinc-HTTP-Server.html a section called 11.3. A Zinc Client.
>
> > 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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
> url: 'https://bittrex.com/api/v1.1/public/getmarkets';
> 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!

Great, I'm glad you're happy.

> 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?

You can map properties (the key/values in JSON maps) using different mechanisms. Directly via instance variables, via accessors and via blocks. In the first two cases, the first approach is indeed to match the names literally. But there are also the variants #mapInstVar:to: and #mapAccessor:to: to have a different name.

  mapping mapInstVar: #markerCurrency to: #MarketCurrency

> * 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?

A mapper (reader or writer) looks for mappings in itself (like how you used it) but also on the class side of schema/class names. So instead of doing the mapping in the construction of the reader/writer you can write a fixed on the class side. Look for implementors of #neoJsonMapping:

The difference is mainly that scope: per reader/writer allows for different mappings depending on use case, while the class side #neoJsonMapping: is global. Some people like a schema definition in one place, other like a distributed one (with inheritance options).

Sven

> cheers -ben
>