Skip to content

Commit e0d800a

Browse files
committed
Updated README.md with details.
1 parent 771668c commit e0d800a

5 files changed

Lines changed: 119 additions & 13 deletions

File tree

README.md

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
# Data Platform APIs HTTP REST Application using HTTPX
1+
# Data Platform APIs HTTP REST Application using Httpx
22

33
- Version: 1.0
44
- Last update: Mar 2026
55
- Environment: Python + JupyterLab + Data Platform Account
66
- Prerequisite: Data Platform access/entitlements
77

8-
Python examples that use [`httpx`](https://www.python-httpx.org/) to authenticate with [LSEG Data Platform APIs](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis) (RDP, also known as Delivery Platform) using OAuth 2.0 Password Grant, then call sample REST endpoints — covering both synchronous and asynchronous patterns.
8+
## Overview
9+
10+
The [Requests](https://requests.readthedocs.io/en/latest/) library is widely regarded as *the de facto* standard HTTP client for Python applications. Many Python developers first learn REST API calls through Requests — including through our [Data Platform APIs Tutorials](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/tutorials) (or you can try RDP HTTP operations with the [built-in http.client](https://docs.python.org/3/library/http.client.html) if you enjoy a challenge.).
11+
12+
That said, there are other Python HTTP libraries worth considering — [HTTPX](https://www.python-httpx.org/), [Aiohttp](https://docs.aiohttp.org/en/stable/), [Urllib3](https://urllib3.readthedocs.io/en/stable/), [Grequests](https://pypi.org/project/grequests/), [PycURL](http://pycurl.io/docs/latest/index.html), and more — each offering different trade-offs in performance and features that may better suit your requirements.
13+
14+
I was drawn to HTTPX because it provides a **requests-compatible API** while also supporting **asynchronous operations** out of the box. That combination made migrating from Requests to HTTPX straightforward, with the added benefit of async support when needed.
15+
16+
This project demonstrates how to use [`httpx`](https://www.python-httpx.org/) to authenticate and retrieve data from [LSEG Data Platform APIs](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis) via HTTP endpoints — covering both synchronous and asynchronous patterns for comparison.
17+
18+
**Note**: A basic knowledge of Python [built-in asyncio](https://docs.python.org/3/library/asyncio.html) library is required to understand example codes.
919

1020
## What is Data Platform APIs?
1121

@@ -79,6 +89,69 @@ async def main():
7989
asyncio.run(main())
8090
```
8191

92+
## What are Synchronous and Asynchronous Execution Models?
93+
94+
**Synchronous** code runs tasks one at a time in a strict sequence — each task must finish before the next one starts. The application pauses and waits at every blocking call. For example, the `httpx.get()` function call below (equivalent to `requests.get()`) blocks the entire program until the HTTP response arrives:
95+
96+
```python
97+
import httpx
98+
99+
def fetch(url):
100+
"""Fetch the content of the URL synchronously."""
101+
r = httpx.get(url, verify=False)
102+
print("Fetched:", url, "status:", r.status_code)
103+
return r.text
104+
105+
def main():
106+
""" Main function."""
107+
fetch("https://example.org")
108+
print("This line prints ONLY after the request is done!")
109+
110+
if __name__ == "__main__":
111+
main()
112+
```
113+
114+
![synchronous code result](images/01_httpx_sync.png)
115+
116+
If the HTTP request takes 60 seconds, the program idles for those 60 seconds before executing the next line. For a single request this is fine, but it becomes a bottleneck when you need to fetch data for many symbols or endpoints.
117+
118+
On the other hand, **Asynchronous** code allows multiple tasks to run concurrently in a non-blocking manner. While one task is waiting for I/O (such as a network response), the event loop can hand control to another task (execute next line of codes) instead of sitting idle. The example below uses `asyncio.create_task()` to launch a fetch in the background and immediately continues to the next line — without waiting for the response:
119+
120+
```python
121+
import asyncio
122+
import httpx
123+
124+
async def fetch(url):
125+
"""Fetch the content of the URL asynchronously."""
126+
async with httpx.AsyncClient(verify=False) as client:
127+
r = await client.get(url)
128+
print("Fetched:", url, "status:", r.status_code)
129+
return r.text
130+
131+
async def main():
132+
""" Main function."""
133+
asyncio.create_task(fetch("https://example.org"))
134+
print("Task launched and not awaited!")
135+
# Sleep to allow the fetch task to complete before the program exits.
136+
await asyncio.sleep(2)
137+
if __name__ == "__main__":
138+
asyncio.run(main())
139+
```
140+
141+
![asynchronous code result](images/02_httpx_async.png)
142+
143+
The real payoff of async comes when you have **many requests to make**. With `asyncio.gather()`, you can fire all of them concurrently so the total wall-clock time is roughly that of the single slowest response — instead of the sum of all response times. That is exactly the pattern used in `example_async_gather.py` and `async_call_nb.ipynb` examples for fetching multiple RICs.
144+
145+
## Prerequisites
146+
147+
- Python 3.11+ (required for `asyncio.TaskGroup` and `except*`)
148+
- LSEG Data Platform credentials with Historical Pricing permission:
149+
- Machine ID
150+
- Password
151+
- AppKey
152+
153+
If you do not have access yet, contact your LSEG representative or account manager.
154+
82155
## Project Structure
83156

84157
```
@@ -171,15 +244,7 @@ Demonstrates:
171244
- `POST /auth/oauth2/v1/revoke` — session revocation using HTTP Basic Auth
172245
- Per-call `verify=False` passed directly to each `httpx` function
173246

174-
## Prerequisites
175247

176-
- Python 3.11+ (required for `asyncio.TaskGroup` and `except*`)
177-
- LSEG RDP credentials:
178-
- Machine ID
179-
- Password
180-
- AppKey
181-
182-
If you do not have access yet, contact your LSEG representative or account manager.
183248

184249
## Setup
185250

@@ -235,7 +300,15 @@ Apache 2.0. See [LICENSE.md](LICENSE.md).
235300

236301
## References
237302

238-
- https://realpython.com/async-io-python/
239-
- https://www.twilio.com/en-us/blog/asynchronous-http-requests-in-python-with-httpx-and-asyncio
240-
- https://docs.python.org/3/library/asyncio-task.html#task-groups
303+
For further details, please check out the following resources:
304+
305+
- [LSEG Data Platform](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis) on the [LSEG Developers Portal](https://developers.lseg.com/en/) website.
306+
- [HTTPX library](https://www.python-httpx.org/) and [GitHub](https://github.com/encode/httpx) pages.
307+
- [Python Asyncio library](https://docs.python.org/3/library/asyncio.html) page.
308+
- [Python's asyncio: A Hands-On Walkthrough](https://realpython.com/async-io-python/)
309+
- [Asynchronous HTTP Requests in Python with HTTPX and asyncio](https://www.twilio.com/en-us/blog/asynchronous-http-requests-in-python-with-httpx-and-asyncio)
310+
- [Asyncio gather function document](https://docs.python.org/3/library/asyncio-task.html#asyncio.gather) page.
311+
- [Asyncio TaskGroup function document](https://docs.python.org/3/library/asyncio-task.html#task-groups) page.
312+
313+
For any questions related to Data Platform APIs, please use the [Developers Community Q&A page](https://community.developers.refinitiv.com/).
241314

images/01_httpx_sync.png

24.7 KB
Loading

images/02_httpx_async.png

23.5 KB
Loading

src/async_example.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import asyncio
2+
import httpx
3+
4+
async def fetch(url):
5+
"""Fetch the content of the URL asynchronously."""
6+
async with httpx.AsyncClient(verify=False) as client:
7+
r = await client.get(url)
8+
print("Fetched:", url, "status:", r.status_code)
9+
return r.text
10+
11+
async def main():
12+
""" Main function."""
13+
asyncio.create_task(fetch("https://example.org"))
14+
print("Task launched and not awaited!")
15+
# Sleep to allow the fetch task to complete before the program exits.
16+
await asyncio.sleep(2)
17+
if __name__ == "__main__":
18+
asyncio.run(main())

src/sync_example.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import httpx
2+
3+
def fetch(url):
4+
"""Fetch the content of the URL synchronously."""
5+
r = httpx.get(url, verify=False)
6+
print("Fetched:", url, "status:", r.status_code)
7+
return r.text
8+
9+
def main():
10+
""" Main function."""
11+
fetch("https://example.org")
12+
print("This line prints ONLY after the request is done!")
13+
14+
if __name__ == "__main__":
15+
main()

0 commit comments

Comments
 (0)