Let's try to monitor crypto assets through the Coinmarketcap API, with Elixir!

Topics I want to explore in this exercise are:

  • Elixir Supervision trees
  • HTTP calls with Elixir (with HTTPoison)
  • TDD and Refactoring

Get crypto assets quotes

Example with cURL

First things first. Are we able to make a simple (authenticated) HTTP call to the coinmarketcap API? I surely think so.

In curl this would be like this (use your own API Key):

curl -H "X-CMC_PRO_API_KEY: YOUR_COINMARKETCAP_API_KEY" -H "Accept: application/json" -d "symbol=BTC" -d "convert=EUR" -G https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest

The command above contacts the Coinmarketcap API to get the latest quote (conversion rate) of Bitcoin related to FIAT EUR.

Note: this is a contrived example, as there is another endpoint (namely /v1/cryptocurrency/listings/latest) to get multiple quotes in a single API call

The response looks like this:

{
  "status": {
    "timestamp": "2020-04-28T06:46:09.890Z",
    "error_code": 0,
    "error_message": null,
    "elapsed": 14,
    "credit_count": 1,
    "notice": null
  },
  "data": {
    "BTC": {
      "id": 1,
      "name": "Bitcoin",
      "symbol": "BTC",
      "slug": "bitcoin",
      "num_market_pairs": 7965,
      "date_added": "2013-04-28T00:00:00.000Z",
      "tags": [
        "mineable"
      ],
      "max_supply": 21000000,
      "circulating_supply": 18349112,
      "total_supply": 18349112,
      "is_active": 1,
      "platform": null,
      "cmc_rank": 1,
      "is_fiat": 0,
      "last_updated": "2020-04-28T02:45:58.000Z",
      "quote": {
        "EUR": {
          "price": 7175.97279154951,
          "volume_24h": 32035162374.6573,
          "percent_change_1h": 0.07515773,
          "percent_change_24h": 0.45923884,
          "percent_change_7d": 12.62102123,
          "market_cap": 131672728461.0946,
          "last_updated": "2020-04-28T06:45:04.000Z"
        }
      }
    }
  }
}

One could say: "Bravo Christian, you can use curl with a copy-pasted example. What about Elixir?"

Example with HTTPoison

Add the dependency HTTPoison to your mix.exs (mix new YOUR_APP_NAME if you're not in an existing application):

...
  defp deps do
    [
      {:httpoison, "~> 1.6"}
    ]
  end
...

Use iex -S mix to enter an interactive shell:

HTTPoison.get! "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest"

This results in a bad response, since the API Key is missing.

Let's see the documentation for "HTTPoison.get!" with h: For more information about h see IEx Helpers.

h HTTPoison.get!

Yielding:

                  def get!(url, headers \\ [], options \\ [])

  @spec get!(binary(), headers(), Keyword.t()) ::
          HTTPoison.Response.t() | HTTPoison.AsyncResponse.t()

Issues a GET request to the given url, raising an exception in case of failure.

If the request does not fail, the response is returned.

See request!/5 for more detailed information.

Now that we know that HTTPoison.get! takes a second argument, namely the headers, let's try to pass them to the function:

headers = ["X-CMC_PRO_API_KEY": "YOUR_API_KEY", "Accept": "Application/json; Charset=utf-8"]
HTTPoison.get! "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest", headers

Almost! We're missing some required fields, namely id, symbol or slug:

headers = ["X-CMC_PRO_API_KEY": "YOUR_API_KEY", "Accept": "Application/json; Charset=utf-8"]
HTTPoison.get! "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?symbol=BTC&convert=EUR", headers

Finally! A %HTTPoison.Response struct is returned with the property body.

Let's test it

Found this little gem about Elixir Test Mocking with Mox.

The general advice is:

Define a behaviour for the CoinmarketcapClient (read more about Elixir behaviours) so that only during tests, a mock behaviour is used for testing purposes.

to be continued