Pagination
Most Variational API endpoints that can return multiple results limit the number of objects returned by a single call. This means that a pagination mechanism must be used to retrieve more objects.
Endpoints using pagination can be identified by the presence of the top-level pagination
key in the JSON data they return. In the Endpoint Reference their Python SDK return value is marked as ApiPage[T]
.
Different endpoints return different number of items on a single page. The Endpoint Reference specifies this number for each endpoint.
Example
When requesting the first page of trades, the response will contain query string parameters required to request the next page.
Example first request:
GET https://api.testnet.variational.io/v1/portfolio/trades?pool=daf1b8ef-bac8-47a0-8d41-f18c9aed8442
Example response:
{
"result": [{ ... }, { ... }, ...],
"pagination": {
"next_page": {
"limit": "1000",
"offset": "1000"
}
}
}
This means that the next page can be retrieved using the URL:
GET https://api.testnet.variational.io/v1/portfolio/trades?pool=daf1b8ef-bac8-47a0-8d41-f18c9aed8442&limit=1000&offset=1000
The last page of the results will still contain the pagination
key but next_page
inside of it will be null:
{
"result": [{ ... }, { ... }, ...],
"pagination": {
"next_page": null
}
}
Python SDK
For flexibility, the Python SDK Client
methods don't perform the pagination automatically:
from variational import Client, TESTNET
client = Client(API_KEY, API_SECRET, base_url=TESTNET)
trades_resp = client.get_portfolio_trades(pool="daf1b8ef-bac8-47a0-8d41-f18c9aed8442")
trades = trades_resp.result # only the first page of trades
Manual Pagination
If necessary, the next page can be retrieved afterward:
if trades_resp.pagination.next_page:
next_resp = client.get_portfolio_trades(
pool="daf1b8ef-bac8-47a0-8d41-f18c9aed8442",
page=trades_resp.pagination.next_page
)
next_trades = next_resp.result
Using the Helper
To avoid boilerplate, the SDK provides a helper generator function paginate()
that yields the requested objects making API calls lazily while it's being consumed.
Signature:
def paginate(method: Callable[..., ApiPage[T]],
*args, page=None, **kwargs) -> Generator[T, None, None]
This code fetches all trades from the previous example into a list using the helper function:
from variational import paginate
# Note that we don't call `client.get_portfolio_trades` here,
# but rather pass a reference to it to `paginate()`.
# All parameters meant for `client.get_portfolio_trades`
# should be passed to `paginate()`.
# `list()` is meant to consume all results from the generator
# at once and eagerly request all pages.
all_trades = list(paginate(client.get_portfolio_trades,
pool="daf1b8ef-bac8-47a0-8d41-f18c9aed8442"))
An example making use of lazy pagination:
pool_id = "daf1b8ef-bac8-47a0-8d41-f18c9aed8442"
for trade in paginate(client.get_portfolio_trades, pool=pool_id):
if is_this_the_last_trade_we_need(trade):
break # no more API calls requesting subsequent pages will happen after this
Logging
If you have a large amount of activity in your account, it might take multiple requests and a significant amount of time to fetch all resulting objects using pagination. Running multiple pagination requests back to back makes it likely to run into Rate Limits. The SDK Client retries them automatically by default but the entire operation will become slowed down.
It might be useful to enable logging in your application to get an indication of progress.
A simple logging configuration that enables debug-level logging for all facilities:
import logging
# run this before initializing variational.Client
logging.basicConfig(
format="[%(levelname)s] %(asctime)s %(name)s %(message)s",
level=logging.DEBUG
)
Advanced configuration enabling only relevant loggers:
import logging, logging.config
logging.config.dictConfig({
"version": 1,
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "default",
}
},
"formatters": {
"default": {
"format": logging.BASIC_FORMAT,
"datefmt": "%Y-%m-%d %H:%M:%S",
}
},
"loggers": {
"variational": { # logs specific to Variational
"handlers": ["console"],
"level": "DEBUG",
"propagate": True,
},
"urllib3.connectionpool": { # logs of all HTTP requests being made
"handlers": ["console"],
"level": "DEBUG",
},
}
})
Last updated