When you interact with SAS Viya’s REST services regularly, the difference between ad‑hoc one‑off requests and a proper HTTP client is night and day. Python’s httpx.Client gives you connection pooling , strict timeouts , optional HTTP/2 , and a clean way to share configuration across calls—all of which translate into faster, safer, and more maintainable integrations with the Viya Folders API.
This post explains why httpx.Client is a great fit and then walks through a compact, production‑lean setup for the following examples:
All endpoint behaviors are based on the official Folders API .
The Folders service, a SAS provided REST API endpoint, organizes SAS and external content in a hierarchical structure. Key operations we’ll use are:
For permissions, predefined folders (like /Public ), and broader concepts, see the SAS Viya Help Center “Folders” guide.
We’ll use a client‑credentials OAuth2 flow to obtain an access token from SASLogon ( /SASLogon/oauth/token ).
Replace BASE_URL , CLIENT_ID , and CLIENT_SECRET with your environment settings. Ideally, they should be stored in .env file.
# auth.py
import httpx
BASE_URL = "https://viya.example.com"
TOKEN_URL = f"{BASE_URL}/SASLogon/oauth/token"
CLIENT_ID = "myclient"
CLIENT_SECRET = "mysecret"
CERT_LOC = "certificate.crt"
def get_access_token(username: str, password:str) -> str:
headers = {
"Content-Type": "application/x-www-form-urlencoded",
}
data = {"grant_type": "password", "username": username, "password": password}
ctx = ssl.create_default_context(cafile=CERT_LOC)
with httpx.Client(timeout=15.0, verify=ctx) as s:
r = s.post(TOKEN_URL, auth=(CLIENT_ID, CLIENT_SECRET), headers=headers, data=data)
r.raise_for_status()
return r.json()["access_token"]
Now that we have the token, let's build a pooled httpx.Client that shares headers, base URL, timeouts, and optional HTTP/2.
Replace BASE_URL, and CERT_LOC with your environment settings.
# client.py
import httpx
BASE_URL = "https://viya.example.com"
CERT_LOC = "certificate.cert"
def build_client(access_token: str) -> httpx.Client:
timeout = httpx.Timeout(connect=5.0, read=30.0, write=15.0, pool=5.0) # strict timeouts
ctx = ssl.create_default_context(cafile=CERT_LOC)
return httpx.Client(
base_url=BASE_URL,
headers={
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
},
timeout=timeout,
verify=ctx
)
This pattern is perfect when you only know a human‑friendly path like /Public/Examples. We first resolve the folder, then list its first 10 members with paging parameters.
# resolve_and_list.py
from auth import get_access_token
from client import build_client
token = get_access_token()
with build_client(token) as s:
# Resolve by path (must match exactly one folder)
r = s.get("/folders/folders/@item", params={"path": "/Products"})
r.raise_for_status()
folder = r.json()
print("Resolved:", folder["name"], folder["id"])
# List first 10 members (paging supported on members endpoints)
m = s.get(f"/folders/folders/{folder['id']}/members", params={"start": 0, "limit": 10})
m.raise_for_status()
names = [it["name"] for it in m.json().get("items", [])]
print("Members:", names)
POST /folders creates a folder; specify parentFolderUri to create a subfolder. The service enforces unique names at a given level , returning 409 Conflict if the name is already taken. DELETE /folders/{id} supports ?recursive=true when the target isn’t empty.
# create_and_delete.py
from auth import get_access_token
from client import build_client
token = get_access_token()
with build_client(token) as s:
parent = s.get("/folders/@item", params={"path": "/Public/Examples"})
parent.raise_for_status()
parent_uri = parent.json()["links"]["self"]["href"]
# Create subfolder
payload = {"name": "Demo", "type": "folder"}
params = {"parentFolderUri": parent_uri}
demo = s.post("/folders", json=payload, params=params, timeout=60)
demo.raise_for_status()
demo_obj = demo.json()
print("Created:", demo_obj["id"], demo_obj["name"])
# Clean-up (recursive delete if needed)
delete = s.delete(f"/folders/{demo_obj['id']}", params={"recursive": "true"})
delete.raise_for_status()
print("Deleted:", demo_obj["id"], demo_obj["name"])
Using httpx.Client with the SAS Viya REST APIs offers a powerful combination of performance, reliability, and developer ergonomics. Thanks to connection pooling and shared configuration, a single client instance reduces latency and eliminates repetitive boilerplate calls when compared to ad‑hoc calls, aligning with httpx’s documented benefits of efficient network usage and centralized settings. Fine‑grained timeout controls help prevent stalled processes and ensure predictable behavior even when interacting with large folder hierarchies or under variable network conditions, reflecting httpx’s strict enforcement of connect/read/write/pool timeouts.
For SAS developers and architects, this translates into integrations that are faster, safer, and easier to maintain —whether you’re resolving paths, listing members, provisioning folder structures, or building idempotent automation routines. Combined with the SAS Viya REST API’s predictable behaviors—clear uniqueness rules, structured paths, and rich metadata— httpx.Client becomes a natural fit for building robust tooling around Viya.
In short, if you work regularly with SAS REST endpoints, adopting httpx.Client is not just a convenience—it’s a foundational step toward writing production‑grade, resilient, and scalable API integrations.
Find more articles from SAS Global Enablement and Learning here.
The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.