Fetch JSON

Grabbing JSON from some url is very easy.

strandio includes the fetch-json function which will handle the HTTP request, response, and parsing, producing json.

The following thread fetches the current Bitcoin price from the CoinGecko API in the specified currency and prints it to the terminal.

btc-price.hoon

/- spider
/+ *strandio
=, strand=strand:spider
=, dejs-soft:format
=, strand-fail=strand-fail:libstrand:spider
^- thread:spider
|= arg=vase
=/ m (strand ,vase)
^- form:m
=/ url
"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies="
=/ cur !<((unit @tas) arg)
?~ cur (strand-fail %no-arg ~)
=. u.cur (crip (cass (trip u.cur)))
?. ((sane %tas) u.cur) (strand-fail %bad-currency-format ~)
;< =json bind:m (fetch-json (weld url (trip u.cur)))
=/ price=(unit @ta) ((ot ~[bitcoin+(ot [u.cur no]~)]) json)
?~ price ((slog 'Currency not found.' ~) (pure:m !>(~)))
%- (slog leaf+"{(trip u.price)} {(cuss (trip u.cur))}" ~)
(pure:m !>(~))

Save it as /ted/btc-price.hoon in the %base desk of a fake ship, |commit %base and run it with -btc-price %usd. You should see something like:

> -btc-price %usd
49168 USD

You can try with other currencies as well:

> -btc-price %nzd
72455 NZD
> -btc-price %aud
68866 AUD
> -btc-price %gbp
37319 GBP

Analysis

The thread takes an @tas as its argument, which the dojo wraps in a unit. We extract the vase and check it's not empty:

=/ cur !<((unit @tas) arg)
?~ cur (strand-fail %no-arg ~)

We then convert it to lowercase and check it's a valid @tas:

=. u.cur (crip (cass (trip u.cur)))
?. ((sane %tas) u.cur) (strand-fail %bad-currency-format ~)

Next, we use the fetch-json function in strandio like so:

;< =json bind:m (fetch-json (weld url (trip u.cur)))

We convert the currency to a tape and weld it to the end of the url, which we give as an argument to fetch-json. The fetch-json function will make the request to the URL, receive the result, parse the JSON and produce the result as a json structure.

The JSON the API produces looks like:

{
"bitcoin": {
"usd": 49477
}
}

Since it's an object in an object, we decode them using nested ot:dejs-soft:format functions, and the price itself using no:dejs-soft:format to produce a (unit @ta):

=/ price=(unit @ta) ((ot ~[bitcoin+(ot [u.cur no]~)]) json)

Finally, we check if the unit is null and either print an error or print the price to the terminal with slog functions (the thread itself produces ~):

?~ price ((slog 'Currency not found.' ~) (pure:m !>(~)))
%- (slog leaf+"{(trip u.price)} {(cuss (trip u.cur))}" ~)
(pure:m !>(~))

For more information about working with json, see the JSON Guide.