API
An application programming interface (API) is a set of rules and protocols that allows one software application to interact with another. In other words, it is a way to communicate with a server. Some of these servers are openly available and host data that can be accessed by anyone. Others require authentication and are therefore paid services.
To illustrate the practical interaction with APIs, we will retrieve cryptocurrency data from the CoinCap API.
We will pull a list of available cryptocurrencies, the latest price history of a specific coin, plot a line chart to visualize the data and lastly perform a conversion from USD to EUR.
Disclaimer
This section merely demonstrates APIs on the example of cryptocurrency market data.
Cryptocurrencies involve significant financial risk. Investors should conduct thorough research and consult financial professionals before making investment decisions. The code examples presented herein are for illustrative purposes only and do not constitute financial advice nor do we endorse any companies mentioned.
Reading the documentation
Open the CoinCap API documentation (here) and browse through the site for a minute or two.
Rate limits
During the task, you should have noticed that the API provides information on rate limits. Rate limits are the number of requests that can be made to the server in a given time frame. If you as the user exceed the rate limit, the server will respond with an error message. In this specific case, we can make up to 200 requests per minute which is more than enough for our use case. These rate limits are set by the provider and can vary from one API to another. Some APIs may not have any rate limits at all.
But how can we even request data from the server to retrieve a list of cryptocurrencies? To answer this question, the concept of endpoints is introduced.
Endpoints
An endpoint is a specific URL that the API uses to perform a specific action.
For example, the endpoint /assets
returns a list of all cryptocurrencies.
To send a request to the server, we need to specify the endpoint in the URL.
The server will then respond with the requested data (if everything went
smoothly).
To request all cryptocurrencies, we can use the following URL:
https://api.coincap.io/v2
is simply the URL of the API and /assets
is
the endpoint of our interest.
Send your first request
Open the URL https://api.coincap.io/v2/assets
in your browser and
observe the response.
Which Python type does the output of your request most closely resemble?
Since we don't want to manually use the browser anytime we want to retrieve
data, we now replicate the request in Python
.
To send requests we can make use of the appropriately named
requests
package.
The below snippet sends a request to the /assets
endpoint and stores the
response in a variable.
import requests
response = requests.get(url="https://api.coincap.io/v2/assets")
data = response.json() # assign the response to a variable
Validate the above quiz question
What type is returned by the response.json()
method?
Check the type()
of the data
variable.
Methods
In the above code snippet, we applied requests
get()
method.
The get
method solely retrieves data from the server, that is no data is
changed on the server-side. If you have another look at the CoinCap API docs
you will discover that all endpoints like /assets
, /rates
, or /markets
are prefaced by the GET
method.
Nevertheless, GET
is not the only method, there are also POST
, PUT
,
DELETE
, and PATCH
. Following table provides a brief overview:
Method | Description | requests method |
---|---|---|
GET | Retrieve data from the server | requests.get() |
POST | Create data on the server | requests.post() |
PUT | Update data on the server | requests.put() |
DELETE | Delete data on the server | requests.delete() |
PATCH | Partially update data on the server | requests.patch() |
Don't worry about these methods too much for now as we will continue solely
with GET
methods.
Info
If you need to revisit the topic of HTTP methods or simply want to dive deeper, here's a great article.
Endpoints continued...
Let's revisit the code snippet from above and extend it. After requesting the
/assets
endpoint we convert the response (the dict
) into a tabular
format in order to process the data more easily.
import requests
response = requests.get(url="https://api.coincap.io/v2/assets")
data = response.json()
print(data.keys()) # print all dictionary keys
print(data["data"]) # closer look at the value of the "data" key
dict_keys(['data', 'timestamp'])
[{'id': 'bitcoin', 'rank': '1', 'symbol': 'BTC', 'name': 'Bitcoin', ....]
A closer look at the response reveals that the dict
is nested.
The data
key is of particular interest, since it contains a list of
dictionaries containing information on cryptocurrencies.
We can convert this list to a pandas
DataFrame
.
id | rank | symbol | name | ... |
---|---|---|---|---|
bitcoin | 1 | BTC | Bitcoin | ... |
ethereum | 2 | ETH | Ethereum | ... |
tether | 3 | USDT | Tether | ... |
solana | 4 | SOL | Solana | ... |
xrp | 5 | XRP | XRP | ... |
Info
The content of your DataFrame
can differ slightly as responses
contain the latest data from the server. Since we are dealing with
cryptocurrency market data, changes occur rapidly.
Nevertheless, that's the power of APIs as they allow you to programmatically access up to date information. 🦾
Query parameters
To continue on our quest to visualize the latest price history of a cryptocurrency, we need to settle on a single cryptocurrency. The concept of query parameters is introduced with another practical example.
For the following examples, we will use an emerging (at the time of writing)
cryptocurrency called Pepe-Cash
(more of a meme-coin).
To get access to the price history of Pepe-Cash
, we need to consult the API
documentation and find the appropriate endpoint.
Which endpoint provides the historic market data of a specific cryptocurrency?
With the endpoint name at hand, we can send another request to the server. But first, we need to construct the URL. Expand the code snippet below, if you solved the quiz question.
URL construction
api_url = "https://api.coincap.io/v2"
coin_id = "pepe-cash"
endpoint = f"/assets/{coin_id}/history"
query_params = "?interval=d1" # daily interval (if available)
url = f"{api_url}{endpoint}{query_params}"
Let's walk through the URL construction step by step:
api_url
is the base URL of the API (nothing new here).coin_id
pepe-cash
is the identifier of the cryptocurrency we want to retrieve data for. We have already requested all cryptocurrency identifiers likebitcoin
orethereum
with the/assets
endpoint. Have another look at the table here.endpoint
contains the endpoint name we want to access, in this particular case/assets/pepe-cash/history
.-
query_params
stands for query parameters which are additional parameters that are passed to the server. Think of aPython
function with the endpoint being the function name and the query parameters being the function parameters used for fine-grained control.Query parameters are separated from the URL by a
?
. In this case, we specified?interval=d1
.interval
is the parameter name followed by the valued1
which stands for daily price history intervals. Again, with aPython
function you can think ofinterval=d1
as a named argument.More detailed explanations on both parameters and values are specified in the API documentation.
Finally, we end up with the URL
"https://api.coincap.io/v2/assets/pepe-cash/history?interval=d1"
Request
If you've followed the construction of the URL closely, we can easily send
another request to retrieve market data. This time around it is another GET
request, however with a query parameter.
# construct the URL (same as above)
api_url = "https://api.coincap.io/v2"
coin_id = "pepe-cash"
endpoint = f"/assets/{coin_id}/history"
query_params = "?interval=d1" # daily interval (if available)
url = f"{api_url}{endpoint}{query_params}"
# send the request
response = requests.get(url=url)
Again, convert the response to a DataFrame
and print the first few rows.
pepe_history = response.json()
pepe_history = pd.DataFrame(pepe_history["data"])
print(pepe_history.tail())
priceUsd | time | date |
---|---|---|
0.0176438251661799 | 1726963200000 | 2024-09-22T00:00:00.000Z |
0.0127411915131318 | 1727827200000 | 2024-10-02T00:00:00.000Z |
0.0127704751708670 | 1727913600000 | 2024-10-03T00:00:00.000Z |
0.0131082066240718 | 1728345600000 | 2024-10-08T00:00:00.000Z |
0.0130405021808657 | 1728432000000 | 2024-10-09T00:00:00.000Z |
We are now looking at the daily (if available) price history of Pepe-Cash
in
USD.
Detour: Visualizations
As a bonus we can plot the price history and try to recreate the price charts seen on various market platforms. This Visualizations section is optional and should provide a glimpse into the possibilities of working with APIs.
Regardless of whether you plot the price chart dynamically or statically, two preprocessing steps are necessary.
# convert date and price to their appropriate types
pepe_history["date"] = pd.to_datetime(pepe_history["date"])
pepe_history["priceUsd"] = pepe_history["priceUsd"].astype(float)
Bonus: Styling the plot
If you want to style the dynamic plot further (to more closely resemble the price charts seen on market platforms) adjust colors, labels and add a logo.
fig = px.area(
data_frame=pepe_history,
x="date",
y="priceUsd",
title="Pepe Cash - Price History in USD",
color_discrete_sequence=["#009485"],
template="plotly_dark" # dark theme
)
# add the logo
fig.add_layout_image(
dict(
source="https://cryptologos.cc/logos/pepe-pepe-logo.png?v=035",
xref="paper",
yref="paper",
x=1,
y=1.15,
sizex=0.2,
sizey=0.2,
xanchor="right",
yanchor="top",
)
)
fig.show()
Rate conversion to
Since the price history is in USD, convert the prices to EUR. Conveniently, the API provides an endpoint for current exchange rates.
- Use the appropriate
/rates/{{id}}
endpoint. - Use the identifier (
id
)euro
for the endpoint. - Construct the URL and send a
GET
request. - Extract the exchange rate from the response. Hint:
This time it is easier to deal with the
dict
and not perform a conversion to aDataFrame
. - Convert
pepe_history["priceUsd"]
to EUR.
Start with the given code snippet below:
import requests
# get current Pepe price history in USD
response = requests.get(url="https://api.coincap.io/v2/assets/pepe-cash/history?interval=d1")
pepe_history = pd.DataFrame(response.json()["data"])
pepe_history["priceUsd"] = pepe_history["priceUsd"].astype(float)
# get exchange rate; your solution ...
Conclusion
In this end-to-end example, we have seen how to retrieve data from an API,
store it in a DataFrame
and visualize it. With consecutive requests, we
have pulled a list of cryptocurrencies, the price history of a specific
coin and even converted the prices to EUR.
Despite this specific use case, concepts like rate limits, endpoints, request methods and query parameters were introduced along the way which are universal to APIs.
Apply your knowledge
You should be able to apply your knowledge to other APIs as well. Here are just a couple of other APIs1:
- OpenWeatherMap for weather data
- NASA from astronomy pictures to earth observation data
- Google Search access search results programmatically
- Spotify access Spotify's music data
- Instagram access Instagram's data
The possibilities are endless. 🚀
If you want to dive deeper into APIs, we recommend the following resources:
- HTTP Status Codes: Dive deeper into the server responses and their various status codes.
- FastAPI: Build an API yourself with Python
-
Some of these APIs require authentication or are paid services. ↩