A python library for interacting with HAL+JSON APIs
—
Built-in authentication support for various methods including Basic Auth, OAuth2, and custom authentication schemes. RestNavigator provides flexible session management through integration with the requests library.
Set authentication credentials for all subsequent API requests.
class HALNavigator:
def authenticate(self, auth) -> None:
"""
Set authentication for API requests.
Parameters:
- auth: Authentication object compatible with requests library
(tuple for basic auth, custom auth objects, etc.)
"""Access and configure the underlying requests session for advanced authentication and request customization.
class HALNavigator:
@property
def session(self) -> 'Session':
"""
Requests session object used for all HTTP operations.
Returns:
Session object with authentication and configuration
"""
@property
def headers(self) -> dict:
"""
Session headers dictionary for request customization.
Returns:
Mutable dictionary of session headers
"""from restnavigator import Navigator
# Basic authentication with username/password
api = Navigator.hal('https://api.example.com/')
api.authenticate(('username', 'password'))
# Or set during creation
api = Navigator.hal(
'https://api.example.com/',
auth=('username', 'password')
)
# Access authenticated resources
user_data = api['me']()from restnavigator import Navigator
from requests_oauthlib import OAuth2Session
# Create OAuth2 session
oauth = OAuth2Session('client_id', token={
'access_token': 'your_access_token',
'token_type': 'Bearer'
})
# Use OAuth2 session with navigator
api = Navigator.hal('https://api.example.com/', session=oauth)
# All requests will include OAuth2 authorization
user_profile = api['profile']()import requests
from requests.auth import AuthBase
class CustomAuth(AuthBase):
def __init__(self, api_key):
self.api_key = api_key
def __call__(self, r):
r.headers['Authorization'] = f'ApiKey {self.api_key}'
return r
# Use custom authentication
api = Navigator.hal('https://api.example.com/')
api.authenticate(CustomAuth('your-api-key'))
# Or with session
session = requests.Session()
session.auth = CustomAuth('your-api-key')
api = Navigator.hal('https://api.example.com/', session=session)# Set default headers for all requests
api = Navigator.hal(
'https://api.example.com/',
headers={
'User-Agent': 'MyApp/1.0',
'Accept': 'application/hal+json'
}
)
# Modify session headers after creation
api.headers['X-Custom-Header'] = 'custom-value'
# Headers are inherited by all navigators from the same API
user = api['users', 0]
print(user.headers) # Includes all session headersimport requests
# Create custom session with advanced configuration
session = requests.Session()
# Configure retries
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry_strategy = Retry(
total=3,
status_forcelist=[429, 500, 502, 503, 504],
method_whitelist=["HEAD", "GET", "OPTIONS"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
# Configure timeout
session.timeout = 30
# Use configured session
api = Navigator.hal('https://api.example.com/', session=session)from requests_oauthlib import OAuth2Session
# OAuth2 with automatic token refresh
def token_updater(token):
# Save updated token to secure storage
save_token_to_storage(token)
oauth = OAuth2Session(
'client_id',
token=current_token,
auto_refresh_url='https://api.example.com/oauth/token',
auto_refresh_kwargs={
'client_id': 'client_id',
'client_secret': 'client_secret'
},
token_updater=token_updater
)
api = Navigator.hal('https://api.example.com/', session=oauth)
# Tokens will be automatically refreshed when they expire
data = api['protected-resource']()# Check if navigator is authenticated
def is_authenticated(navigator):
return navigator.session.auth is not None
# Get current authentication type
def get_auth_type(navigator):
auth = navigator.session.auth
if isinstance(auth, tuple) and len(auth) == 2:
return 'basic'
elif hasattr(auth, '__class__'):
return auth.__class__.__name__
return 'none'
# Clear authentication
def clear_auth(navigator):
navigator.session.auth = None
# Usage
print("Authenticated:", is_authenticated(api))
print("Auth type:", get_auth_type(api))# Override authentication for specific requests
result = api['sensitive-endpoint'].create(
data,
headers={'Authorization': 'Bearer special-token'}
)
# Use different auth for specific operations
admin_auth = ('admin', 'admin-password')
admin_result = api['admin']['users'].create(
user_data,
headers={'Authorization': f'Basic {base64.b64encode(b"admin:admin-password").decode()}'}
)# All navigators from the same API root share the same session
api = Navigator.hal('https://api.example.com/')
api.authenticate(('user', 'pass'))
# These navigators share authentication
users = api['users']
posts = api['posts']
# They all use the same session
assert users.session is api.session
assert posts.session is api.session
# Authentication applies to all related navigators
user_data = users[0]() # Uses authenticated session
post_data = posts[0]() # Uses authenticated sessionfrom restnavigator.exc import HALNavigatorError
try:
protected_data = api['protected']()
except HALNavigatorError as e:
if e.status == 401:
print("Authentication required or invalid")
# Re-authenticate or refresh token
api.authenticate(new_credentials)
protected_data = api['protected']()
elif e.status == 403:
print("Insufficient permissions")
else:
raiseInstall with Tessl CLI
npx tessl i tessl/pypi-restnavigator