Skip to content

Commit e972b05

Browse files
committed
Created a runnable prototype for RDP HTTPX client, with a synchronous example. The example demonstrates how to authenticate and call RDP APIs using httpx in blocking mode.
The code includes comments explaining the use of `verify=False` to skip SSL verification for local/dev environments, which is not recommended for production use.
1 parent 3b1dc1a commit e972b05

2 files changed

Lines changed: 84 additions & 13 deletions

File tree

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# RDP_HTTPX
2+
3+
Small Python example that uses [`httpx`](https://www.python-httpx.org/) to authenticate with the Refinitiv Data Platform (RDP) OAuth2 **Password Grant** flow and call a couple of RDP REST endpoints.
4+
5+
## What’s included
6+
7+
- `src/example_sync_httpx.py` – synchronous (blocking) demo script that:
8+
- Authenticates: `POST /auth/oauth2/v1/token`
9+
- Calls Pricing Chains: `GET /data/pricing/chains/v1/`
10+
- Calls Historical Pricing Events: `POST /data/historical-pricing/v1/views/events`
11+
- Refreshes token (refresh_token grant)
12+
- Revokes token: `POST /auth/oauth2/v1/revoke`
13+
14+
## Prerequisites
15+
16+
- Python 3.10+ recommended
17+
- RDP credentials:
18+
- **Machine ID**
19+
- **Password**
20+
- **AppKey**
21+
22+
## Setup
23+
24+
1) Create and activate a virtual environment.
25+
26+
```powershell
27+
python -m venv .venv
28+
.\.venv\Scripts\Activate.ps1
29+
```
30+
31+
2) Install dependencies.
32+
33+
```powershell
34+
pip install -r requirements.txt
35+
```
36+
37+
3) Create your environment file.
38+
39+
Copy `src/.env.example` to `src/.env` and fill in values:
40+
41+
```dotenv
42+
RDP_BASE_URL=https://api.refinitiv.com
43+
44+
MACHINEID_RDP=<RDP Machine-ID>
45+
PASSWORD_RDP=<RDP Password>
46+
APPKEY_RDP=<RDP AppKey>
47+
```
48+
49+
## Run
50+
51+
```powershell
52+
python .\src\example_sync_httpx.py
53+
```
54+
55+
The script prints the access token (demo only), then prints the JSON responses from the sample endpoints.
56+
57+
## Security notes
58+
59+
The example uses `verify=False` in `httpx` calls, which **disables TLS certificate verification**. This is unsafe for production—remove `verify=False` (or provide a proper CA bundle) for real usage. I use it in this project to avoid LSEG beloved ZScaler.
60+
61+
Also avoid printing access tokens in real applications.
62+
63+
## License
64+
65+
Apache 2.0 — see [LICENSE.md](LICENSE.md).

src/example_sync_httpx.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
""" Example code demonstrating how to use httpx to authenticate and call RDP APIs with the requests like interface. This is a synchronous version of the example_httpx.py file, using httpx in blocking mode. """
12
import os
2-
import sys
33
import time
44
import httpx
55
from dotenv import load_dotenv
@@ -20,9 +20,9 @@ def authenticate_rdp(machine_id, password, app_key, url) -> dict:
2020

2121
# Send authentication request to the OAuth token endpoint.
2222
# `data=payload` sends a form body required by this endpoint.
23-
# `verify=False` skips SSL verification (for local/dev only).
23+
# `verify=False` skips SSL verification (for local/dev only). This is not recommended for production use. I use it to avoid LSEG beloved ZScaler.
2424
response = httpx.post(url, data=payload, verify=False)
25-
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors
25+
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors, automatic handles of non-200 responses
2626
return response.json()
2727

2828
def get_chain(ric, token, url) -> dict:
@@ -37,8 +37,9 @@ def get_chain(ric, token, url) -> dict:
3737
"universe": ric
3838
}
3939
# Request chain data from the pricing chains endpoint.
40+
# `verify=False` skips SSL verification (for local/dev only). This is not recommended for production use. I use it to avoid LSEG beloved ZScaler.
4041
response = httpx.get(url, params=parameters, headers=headers, verify=False)
41-
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors
42+
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors, automatic handles of non-200 responses
4243
return response.json()
4344

4445
def post_historical_event(rics, token, url) -> dict:
@@ -55,9 +56,10 @@ def post_historical_event(rics, token, url) -> dict:
5556
}
5657

5758
# `json=payload` serializes and sends JSON in the request body.
59+
# `verify=False` skips SSL verification (for local/dev only). This is not recommended for production use. I use it to avoid LSEG beloved ZScaler.
5860
response = httpx.post(url, json=payload, headers=headers, verify=False)
59-
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors
60-
return response.json()
61+
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors, automatic handles of non-200 responses
62+
return response.json()
6163

6264
def post_authen_refresh(appkey, refresh_token,url) -> dict:
6365
"""Refresh the access token using the refresh token."""
@@ -69,21 +71,22 @@ def post_authen_refresh(appkey, refresh_token,url) -> dict:
6971
headers = {
7072
"Content-Type": "application/x-www-form-urlencoded"
7173
}
74+
# `verify=False` skips SSL verification (for local/dev only). This is not recommended for production use. I use it to avoid LSEG beloved ZScaler.
7275
response = httpx.post(url, data=payload, headers=headers, verify=False)
73-
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors
76+
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors, automatic handles of non-200 responses
7477
return response.json()
7578

76-
def post_authen_revoke(token, appkey, url) -> None:
79+
def post_authen_revoke(token, appkey, url) -> None:
7780
"""Revoke the access token to end the session."""
7881
headers = {
7982
"Content-Type": "application/x-www-form-urlencoded"
8083
}
8184

8285
payload = f"token={token}"
8386
auth = httpx.BasicAuth(username=appkey, password="")
84-
87+
# `verify=False` skips SSL verification (for local/dev only). This is not recommended for production use. I use it to avoid LSEG beloved ZScaler.
8588
response = httpx.post(url, data=payload, headers=headers, auth=auth, verify=False)
86-
response.raise_for_status()
89+
response.raise_for_status() # Raise an exception for 4xx/5xx HTTP errors, automatic handles of non-2xx responses
8790

8891
def main() -> None:
8992
"""Run the end-to-end demo: auth, chain data, and historical events."""
@@ -98,7 +101,7 @@ def main() -> None:
98101

99102
# OAuth token endpoint used to obtain access token.
100103
auth_url = f"{base_url}/auth/oauth2/v1/token"
101-
104+
token_data = {}
102105
try:
103106
token_data = authenticate_rdp(machine_id, password, app_key, auth_url)
104107
print("Authentication successful! Status code: 200")
@@ -110,9 +113,10 @@ def main() -> None:
110113
except httpx.RequestError as e:
111114
# Network-level error (e.g. connection refused, DNS failure, timeout)
112115
print(f"Request error: {e}")
116+
return
113117

114118
# Continue only when an access token is available.
115-
if token_data["access_token"]:
119+
if token_data.get("access_token"):
116120

117121
print("Access token received successfully.")
118122
# Example single RIC lookup for chain endpoint using HTTP GET.
@@ -155,6 +159,7 @@ def main() -> None:
155159
print(f"HTTP error while refreshing token: {e_refresh.response.status_code} - {e_refresh.response.text}")
156160
except httpx.RequestError as e_refresh:
157161
print(f"Request error while refreshing token: {e_refresh}")
162+
return
158163

159164
time.sleep(5) # Sleep for 5 seconds before revoking token (for demo purposes)
160165
revoke_url = f"{base_url}/auth/oauth2/v1/revoke"
@@ -166,9 +171,10 @@ def main() -> None:
166171
print(f"HTTP error while revoking token: {e_revoke.response.status_code} - {e_revoke.response.text}")
167172
except httpx.RequestError as e_revoke:
168173
print(f"Request error while revoking token: {e_revoke}")
174+
return
169175
else:
170176
print("Failed to receive access token. Exiting...")
171-
sys.exit(1)
177+
return
172178

173179

174180
if __name__ == "__main__":

0 commit comments

Comments
 (0)