trustcafe-api-wrapper/README.md
BarnacleBoy 7b4e280a3d Update documentation for APIClient.wrapped and WRAPPERS.md
- Fixed APIClient.wrapped() doc to use job_function instead of job
- Updated WRAPPERS.md parameter tables:
  - update_post(): Corrected all parameters (post_text, post_path, parent_path, post_key, blur_label, card_url, collaborative)
  - create_comment(): Made parent_path optional, added comment_text requirement, clarified post_slug/post_key alternatives

# Conflicts:
#	docs/WRAPPERS.md
2026-04-18 03:44:21 +00:00

661 lines
15 KiB
Markdown

# TrustCafé API Wrapper
A Python wrapper for the TrustCafé API, providing a convenient interface to interact with TrustCafé features programmatically.
## Table of Contents
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Authentication](#authentication)
- [API Reference](#api-reference)
- [Jobs](#jobs)
- [Wrappers](#wrappers)
- [Custom Requests](#custom-requests)
- [Environment Setup](#environment-setup)
- [Debug Mode](#debug-mode)
- [Examples](#examples)
- [Development](#development)
- [Testing](#testing)
## Prerequisites
Before you begin, ensure you have:
- **Python 3.11 or higher** installed
- **API Client ID and Secret** from TrustCafé
- **python-dotenv** (for `.env` file support) or ability to set environment variables
### Getting API Credentials
1. Visit your TrustCafé account page:
- [Production API Access](https://www.trustcafe.io/en/myaccount/apiaccess)
- [Alpha Environment API Access](https://alpha.wts2.net/en/myaccount/apiaccess)
2. Click "Create new client credentials key pair"
3. Choose the scopes you need (or select all for full access)
4. Click "Save"
5. Copy the **client_id** and **client_secret** to your environment:
- The secret cannot be retrieved later — make sure to save it securely
- Do not commit these credentials to version control
## Installation
```bash
# Using pip
pip install trustcafeapiwrapper
# Using uv (recommended)
uv add trustcafeapiwrapper
```
## Quick Start
The simplest way to get started:
```python
import trustcafeapiwrapper
import os
# Initialize the API client
API = trustcafeapiwrapper.APIClient(
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
env="alpha", # Options: "alpha" or "production"
debug=False
)
# Authenticate and get user profile
API.handle_token()
profile = API.run_job('userprofile.get', "your-username")
print(profile)
```
## Authentication
The API wrapper handles OAuth2 client-credentials authentication automatically.
### Automatic Token Management
```python
API.handle_token()
```
**What it does:**
- Checks for an existing token file (`token_data_{env}.json`)
- If found, verifies if the token is still valid
- If expired or not found, obtains a new access token (~3 month duration)
- Saves the token to a local file for future requests
### Manual Token Management
For more control over token storage:
```python
def getMyToken():
# Retrieve token from your custom storage (database, file, etc.)
return {
"access_token": "***",
"access_token_timeout": 9999999999 # Unix timestamp
}
def saveMyToken(token_data):
# Save to your preferred storage
with open("my_token_cache.json", "w") as f:
json.dump(token_data, f)
return True
# Set the token manually or pass to initialize
API = APIClient(
client_id=os.getenv("client_id"),
client_secret=os.getenv("client_secret"),
env="production",
debug=False
)
# Use existing token or get a new one
if not API.is_token_valid():
saveMyToken(API.sign_in())
```
### Token Validation
```python
if API.is_token_valid():
print("Token is valid")
else:
API.handle_token() # Get a new token
```
## Environment Setup
The wrapper supports two environments:
| Environment | URL | Purpose |
|------------|-----|---------|
| `alpha` | `alpha.wts2.net` | Development/staging environment |
| `production` | `trustcafe.io` | Production environment |
```python
# Alpha environment (default)
API = APIClient(
client_id="your-client-id",
client_secret="your-client-secret",
env="alpha",
debug=False
)
# Production environment
API = APIClient(
client_id="your-client-id",
client_secret="your-client-secret",
env="production",
debug=False
)
# Change environment dynamically
API.set_environment("production")
```
## API Reference
### Jobs
Jobs are pre-built functions that map to specific API endpoints. They return the raw response from the API.
#### Post Operations
```python
# Get a specific post
post = API.run_job('post.get', "post-slug-or-id")
# Create a post
post = API.run_job('post.create', {
"postText": "This is a test post",
"parent": {
"pk": "maintrunk#maintrunk",
"sk": "maintrunk#maintrunk"
}
})
# List all posts
posts = API.run_job('post.listall')
# List public posts
public_posts = API.run_job('post.listpublic')
# List posts by a specific branch
branch_posts = API.run_job('post.listbybranch', "branch-name")
# List posts by a user profile
user_posts = API.run_job('post.listbyuserprofile', "username")
# Update a post
updated_post = API.run_job('post.update', {
"pk": "post-id",
"sk": "post-id",
"newPostText": "Updated text"
})
# Delete a post
deleted = API.run_job('post.listremoved', "post-id")
```
#### Comment Operations
```python
# Create a comment
comment = API.run_job('comment.create', {
"commentText": "This is a comment",
"parent": {
"pk": "post-id",
"sk": "post-id"
}
})
# Get comments by post ID
comments = API.run_job('comment.listtbypostid', "post-id")
```
#### User Profile Operations
```python
# Get user profile
profile = API.run_job('userprofile.get', "username")
```
#### Follow Operations
```python
# Follow a user
followed = API.run_job('follow.follow', {
"isFollowing": true,
"parent": {
"pk": "userprofile#username",
"sk": "userprofile#username"
},
"followType": "userprofile",
"parentSlug": "username"
})
```
#### Vote Operations
```python
# Cast a vote
voted = API.run_job('vote.votecast', {
"parent": {
"pk": "post-id",
"sk": "post-id",
"slug": "post-slug",
"entity": "post"
},
"vote": "up" # or "down"
})
```
#### Reaction Operations
```python
# React to something (post, comment, etc.)
reactions = API.run_job('reaction.reacttosomething', {
"parent": {
"pk": "post-id",
"sk": "post-id"
},
"reaction": "like" # various types supported
})
# Get reactions by parent
post_reactions = API.run_job('reaction.getbyparent', "parent-id")
# List reactions
reactions_list = API.run_job('reaction.listbyparent', "parent-id")
```
#### Notification Operations
```python
# List all notifications
notifications = API.run_job('notification.listnotifications')
# Mark all as read
API.run_job('notification.markallasread')
```
#### Trust Operations
```python
# Create or update trust relationship
trust = API.run_job('trust.createorupdate', {
"pk": "trust_id",
"sk": "trust_id",
"trustType": "positive"
})
# List trust by user initialization
trusts = API.run_job('trust.listbyusersinit', "username")
# List trust by user has
trusts = API.run_job('trust.listbyuserhas', "username")
```
#### Branch Operations
```python
# Get a specific branch
branch = API.run_job('branch.get', "branch-name")
# List branches (all branches with pagination)
branches = API.run_job('branch.listbyname')
```
#### Feed Operations
```python
# Get café feed
feed = API.run_job('feed.cafefeed')
# Get following feed
following_feed = API.run_job('feed.followingfeed')
```
#### Block Operations
```python
# Block a user (function exists but needs implementation)
# TODO: Add job function for block operations
```
#### Mute Operations
```python
# Mute functionality (to be added)
# TODO: Add job function for mute operations
```
### Wrappers
Wrappers are high-level functions that simplify common operations by handling payload preparation and job execution automatically.
#### Using a Wrapper
```python
API.handle_token()
# Create a post with a wrapper (recommended for simplicity)
from trustcafeapiwrapper.wrappers.post.create_post import create_post
API.wrapped(create_post(
"This is a test post created via the wrapper.",
parent_path="/", # Root path (optional)
blur_label=None, # Optional blurring
card_url=None, # Optional card URL
collaborative=False # Optional collaboration flag
))
# Create a comment
from trustcafeapiwrapper.wrappers.comment.create_comment import create_comment
API.wrapped(create_comment(
"This is a comment",
parent_path="/" # Parent path (required)
))
```
**About Wrappers:**
- Wrappers simplify common operations
- They prepare the payload and job execution automatically
- More wrappers are being added for consistency
- For flexibility, use Jobs or Custom Requests
**Note on APIClient.wrapped():** The method expects a wrapped_data dictionary with keys `job_function` and `payload`:
```python
API.wrapped({
"job_function": "post.create",
"payload": {...}
})
```
### Using `run_job` vs. Wrappers
| Feature | `run_job` | Wrappers |
|---------|----------|----------|
| Simplicity | Higher | Highest for common tasks |
| Flexibility | Maximum | Optimized for specific use cases |
| Discovery | Need to know job format | Self-documenting payloads |
| Customization | Full control | Pre-defined options |
**Recommendation:**
- Use **Wrappers** for common, well-documented operations
- Use **Jobs** when you need fine-grained control
- Use **Custom Requests** when neither fits your needs
## Custom Requests
For operations not covered by jobs or wrappers, use the `make_request` method:
```python
# Make a raw API request
response = API.make_request(
method="GET",
endpoint="content",
path="post/some-custom-path",
authenticate=True,
query_params={"param1": "value1"}
)
```
**Parameters:**
- `method` (str): HTTP method - "GET", "POST", "PUT", "DELETE"
- `endpoint` (str): API endpoint - "content", "auth", "audrey", etc.
- `path` (str): API path after endpoint
- `authenticate` (bool): Whether to include authentication token
- `query_params` (dict): Optional query parameters
**Example - Custom Request:**
```python
# Get posts from a specific branch with filters
posts = API.make_request(
"GET",
"content",
"post/ref-subwiki/music",
query_params={"limit": 10, "offset": 0}
)
```
## Debug Mode
Enable debug mode to see all API requests and responses:
```python
API = APIClient(
client_id=os.getenv("client_id"),
client_secret=os.getenv("client_secret"),
env="production",
debug=True # Enable debug mode
)
# Now API calls will print request details
API.handle_token()
```
## Examples
### Example 1: Basic Post Creation
```python
import trustcafeapiwrapper
import os
# Setup
API = trustcafeapiwrapper.APIClient(
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
env="alpha",
debug=False
)
# Handle authentication
API.handle_token()
# Create a post in the music branch
from trustcafeapiwrapper.wrappers.post.create_post import create_post
API.wrapped(create_post(
"New music discussion post",
parent_path="/music",
blur_label=None,
card_url=None,
collaborative=False
))
```
### Example 2: Following a User and Getting Their Profile
```python
import trustcafeapiwrapper
import os
API = trustcafeapiwrapper.APIClient(
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
env="production"
)
# Follow a user
follow = API.run_job('follow.follow', {
"isFollowing": true,
"parent": {
"pk": "userprofile#philosopher-jon",
"sk": "userprofile#philosopher-jon"
},
"followType": "userprofile",
"parentSlug": "philosopher-jon"
})
print(f"Followed user: {follow}")
# Get their profile
profile = API.run_job('userprofile.get', "philosopher-jon")
print(f"Profile data: {profile}")
```
### Example 3: Managing Notifications
```python
import trustcafeapiwrapper
import os
API = trustcafeapiwrapper.APIClient(
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
env="production"
)
API.handle_token()
# Check for new notifications
notifications = API.run_job('notification.listnotifications')
print(f"Unread notifications: {notifications}")
# Mark all as read
API.run_job('notification.markallasread')
print("All notifications marked as read")
```
### Example 4: Creating a Collaborative Post
```python
import trustcafeapiwrapper
import os
API = trustcafeapiwrapper.APIClient(
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
env="production"
)
API.handle_token()
# Create a collaborative post
from trustcafeapiwrapper.wrappers.post.create_post import create_post
API.wrapped(create_post(
"Research paper draft - collaborative editing",
parent_path="/research",
collaborative=True # Enables collaborative editing
))
```
## Development
### Project Structure
```
trustcafe-api-wrapper/
├── src/
│ └── trustcafeapiwrapper/
│ ├── apiclient.py # Core API client
│ ├── jobs/ # API job functions
│ │ ├── post/
│ │ ├── comment/
│ │ ├── userprofile/
│ │ ├── follow/
│ │ └── ... (all jobs)
│ ├── wrappers/ # High-level wrappers
│ │ ├── post/
│ │ ├── comment/
│ │ └── ...
│ └── utils/ # Helper functions
├── tests/ # Test files
├── README.md # This file
├── documentation.md # Basic documentation
├── development.md # Project notes
└── pyproject.toml # Project configuration
```
### Adding New Jobs
1. Create a new file in `src/trustcafeapiwrapper/jobs/`
2. Define a function matching the job name
3. Export it from the module's `__init__.py`
4. Document the parameters and return value
**Example - Adding a Job:**
```python
# src/trustcafeapiwrapper/jobs/example/new_job.py
def my_new_job(API, param1: str, param2: int) -> dict:
"""
Create a new job function.
Args:
API: The APIClient instance
param1 (str): Description of parameter 1
param2 (int): Description of parameter 2
Returns:
dict: The API response
"""
response = API.make_request(
"POST",
"endpoint",
"path/to/resource",
data={"param1": param1, "param2": param2}
)
return response
```
### Known Limitations
- **Incomplete Jobs**: Not all available API endpoints have wrapper functions yet
- **Enums**: Some enum types are not strictly typed
- **Block Operations**: Block functionality exists in backend but not yet exposed
- **Mute Operations**: Mute functionality pending implementation
### Future Enhancements
- Complete coverage of all TrustCafé API endpoints
- Type hints for better IDE support
- Async support for better performance
- Comprehensive test suite
- Pydantic models for request/response validation
## Testing
Run the test suite:
```bash
pytest
```
Or run specific tests:
```bash
# Test the API client
python -m pytest tests/apiclient.py
# Run all tests
python -m pytest tests/
```
## License
[Depends on TrustCafé project license]
## Support
For issues, questions, or contributions:
- [TrustCafé Website](https://trustcafe.io)
- [GitLab Repository](https://gitlab.com/trustcafe/trustcafe-api-wrapper)
- Contact the WikiTribune team
## Version History
- **0.1.0.13** - Current version with ongoing development
---
**Note:** This wrapper is for internal WikiTribune/TrustCafé use. Public API endpoints are subject to change.