- env= -> environment= across all docs (Pydantic silently ignores env=) - Remove __version__ check (doesn't exist in module) - Fix APIClient(debug=True) missing required client_id/secret - Fix post.listremoved usage (takes no postId, just lists removed posts) - Fix JS true/false -> Python True/False in code blocks - Fix parameter names: branchName->branch_slug, username->user_slug, postId->post_id - Add missing lastEvaluatedKey param docs for list jobs - Note post.listpublic as unauthenticated endpoint - Fix pagination examples (LastEvaluatedKey, not ExclusiveStartKey dict) - Remove non-existent headers param from make_request example - Fix branch.listbyname example (takes no name arg) - Add 4 missing wrapper docs: follow, react, trust, votecast - Fix broken internal links (case-sensitive filenames) - Fix <environment>_handle_token template artifact - Add CODE_BUGS.md documenting 4 code bugs found during audit
741 lines
17 KiB
Markdown
741 lines
17 KiB
Markdown
# TrustCafé API Wrapped Functions Guide
|
|
|
|
This guide covers the high-level wrapper functions provided by the TrustCafé API wrapper. Wrappers simplify common operations by handling payload preparation and job execution automatically.
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Post Wrappers](#post-wrappers)
|
|
- [Comment Wrappers](#comment-wrappers)
|
|
- [Interaction Wrappers](#interaction-wrappers)
|
|
- [Wrappers Best Practices](#wrappers-best-practices)
|
|
- [Wrapper vs Job](#wrapper-vs-job)
|
|
|
|
## Overview
|
|
|
|
### What are Wrappers?
|
|
|
|
Wrappers are pre-built functions that encapsulate common TrustCafé API operations. They:
|
|
|
|
- **Simplify usage**: Less boilerplate code
|
|
- **Handle payload preparation**: Automatically structure requests
|
|
- **Prevent errors**: Built-in validation and defaults
|
|
- **Self-documenting**: Clear parameter names and descriptions
|
|
|
|
### When to Use Wrappers
|
|
|
|
**Use Wrappers for:**
|
|
- Creating and managing content (posts, comments)
|
|
- Standard operations with predictable inputs
|
|
- Reducing code complexity
|
|
- Frequently used patterns
|
|
|
|
**Use Jobs or Custom Requests when:**
|
|
- More control is needed
|
|
- Custom parameter combinations
|
|
- Operations not covered by wrappers
|
|
- Uncommon workflows
|
|
|
|
### Quick Example
|
|
|
|
```python
|
|
# Using a wrapper (RECOMMENDED)
|
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
|
|
|
API.wrapped(create_post(
|
|
"This is my post content",
|
|
parent_path="/music"
|
|
))
|
|
|
|
# Using a job (for custom control)
|
|
API.run_job('post.create', {
|
|
"postText": "Different content",
|
|
"parent": {
|
|
"pk": "parents-key",
|
|
"sk": "parents-key"
|
|
}
|
|
})
|
|
```
|
|
|
|
## Post Wrappers
|
|
|
|
### create_post()
|
|
|
|
Creates a new post with simplified parameters.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
|
|
|
API.wrapped(create_post(
|
|
post_text="Post content here",
|
|
parent_path="/branch-name",
|
|
blur_label=None,
|
|
card_url=None,
|
|
collaborative=False
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `post_text` | str | **Required** | The text content of the post |
|
|
| `parent_path` | str | `"/"` | Branch path where the post will be created |
|
|
| `blur_label` | str | `None` | Optional label for blurring content |
|
|
| `card_url` | str | `None` | Optional URL for card preview |
|
|
| `collaborative` | bool | `False` | Enable collaborative editing |
|
|
|
|
**Returns:** dict - Job execution result, contains success information
|
|
|
|
**Example - Basic Post:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
|
|
|
API.handle_token()
|
|
|
|
API.wrapped(create_post(
|
|
"Welcome to TrustCafé!",
|
|
parent_path="/"
|
|
))
|
|
```
|
|
|
|
**Example - Post in a Specific Branch:**
|
|
|
|
```python
|
|
API.wrapped(create_post(
|
|
"Music discussion thread",
|
|
parent_path="/music",
|
|
blur_label=None,
|
|
card_url=None,
|
|
collaborative=False
|
|
))
|
|
```
|
|
|
|
**Example - Blurred Post:**
|
|
|
|
```python
|
|
API.wrapped(create_post(
|
|
"Sensitive information",
|
|
parent_path="/",
|
|
blur_label="secret", # Will blur until labeled
|
|
card_url=None,
|
|
collaborative=False
|
|
))
|
|
```
|
|
|
|
**Example - Collaborative Post:**
|
|
|
|
```python
|
|
API.wrapped(create_post(
|
|
"Research paper draft - collaborative editing",
|
|
parent_path="/research",
|
|
blur_label=None,
|
|
card_url=None,
|
|
collaborative=True # Enables real-time collaboration
|
|
))
|
|
```
|
|
|
|
Example of performing multi-step integration with create_post and a linked resource:
|
|
```python
|
|
# Create post
|
|
created = API.wrapped(create_post("Paper title / author", parent_path="/research"))
|
|
|
|
# If response includes pk/sk, attach a linked item (structure depends on TrustCafé's link feature)
|
|
API.run_job('some.link.create', {
|
|
"fromPK": "paper",
|
|
"fromSK": created.get('pk'),
|
|
"toPK": "external-source",
|
|
"toSK": created.get('sk')
|
|
})
|
|
```
|
|
|
|
### update_post()
|
|
|
|
Updates an existing post.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.post.update_post import update_post
|
|
|
|
API.wrapped(update_post(
|
|
post_text="New post content",
|
|
parent_path="/branch-name"
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `post_text` | str | **Required** | The new text for the post |
|
|
| `post_path` | str | `None` | The path of the post to update |
|
|
| `parent_path` | str | `"/"` | The parent path for the post |
|
|
| `post_key` | dict | `None` | A dictionary containing `pk` and `sk` of the post |
|
|
| `blur_label` | str | `None` | Optional blur label for the post |
|
|
| `card_url` | str | `None` | Optional card URL for the post |
|
|
| `collaborative` | bool | `False` | Whether the post is collaborative |
|
|
|
|
**Returns:** dict - Updated post data
|
|
|
|
**Note:** You must provide either:
|
|
- Both `post_path` and `parent_path`, or
|
|
- The `post_key` dict with `pk` and `sk`
|
|
|
|
**Example - Update Text:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.post.update_post import update_post
|
|
|
|
API.handle_token()
|
|
|
|
API.wrapped(update_post(
|
|
post_text="Updated content here",
|
|
parent_path="/music"
|
|
))
|
|
```
|
|
|
|
**Example - Update with Optional Fields:**
|
|
|
|
```python
|
|
API.wrapped(update_post(
|
|
post_text="Updated with new card",
|
|
parent_path="/music",
|
|
card_url="https://example.com/resource"
|
|
))
|
|
```
|
|
|
|
**Example - Update Using post_key:**
|
|
|
|
```python
|
|
API.wrapped(update_post(
|
|
post_text="Updated via key",
|
|
post_key={
|
|
"pk": "post-id",
|
|
"sk": "post-id"
|
|
}
|
|
))
|
|
```
|
|
|
|
**Example - Update Blur Label:**
|
|
|
|
```python
|
|
API.wrapped(update_post(
|
|
post_text="Sensitive content",
|
|
parent_path="/",
|
|
blur_label="sensitive"
|
|
))
|
|
```
|
|
|
|
See update_post.py for full mapping of updated fields to the server payload.
|
|
|
|
## Comment Wrappers
|
|
|
|
### create_comment()
|
|
|
|
Creates a new comment on a post.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.comment.create_comment import create_comment
|
|
|
|
API.wrapped(create_comment(
|
|
comment_text="This is a comment"
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `comment_text` | str | **Required** | The comment content |
|
|
| `post_slug` | str | `None` | The slug of the post the comment belongs to |
|
|
| `parent_path` | str | `None` | Parent path (`userprofile/slug` or `subwiki/slug`) |
|
|
| `post_key` | dict | `None` | Dictionary containing `pk` and `sk` of the post |
|
|
| `blur_label` | str | `None` | Optional label for blurring comment content |
|
|
| `version` | int | `3` | Version of comment structure to use |
|
|
|
|
**Returns:** dict - Job execution result, contains success information
|
|
|
|
**Note:** You must provide either:
|
|
- The `post_key` dict with `pk` and `sk`, or
|
|
- Both `post_slug` and `parent_path`
|
|
|
|
**Example - Basic Comment:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.comment.create_comment import create_comment
|
|
|
|
API.handle_token()
|
|
|
|
API.wrapped(create_comment(
|
|
"Great post! I really enjoyed reading it."
|
|
))
|
|
```
|
|
|
|
**Example - Comment on a Post by Slug:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.comment.create_comment import create_comment
|
|
|
|
API.handle_token()
|
|
|
|
API.wrapped(create_comment(
|
|
"I agree with your point about this.",
|
|
post_slug="target-post-slug",
|
|
parent_path="/branch-name"
|
|
))
|
|
```
|
|
|
|
**Example - Comment on a Post by post_key:**
|
|
|
|
```python
|
|
API.wrapped(create_comment(
|
|
"Let's work on this together!",
|
|
post_key={
|
|
"pk": "post-id",
|
|
"sk": "post-id"
|
|
}
|
|
))
|
|
```
|
|
|
|
**Example - Collaborative Comment:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.comment.create_comment import create_comment
|
|
|
|
API.wrapped(create_comment(
|
|
"Let's work on this together!",
|
|
post_slug="current-post-slug",
|
|
parent_path="/research"
|
|
))
|
|
```
|
|
|
|
## Interaction Wrappers
|
|
|
|
### follow()
|
|
|
|
Follow or unfollow a user or branch.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.follow.follow import follow
|
|
|
|
API.wrapped(follow(
|
|
entity="userprofile",
|
|
is_following=True,
|
|
parent_slug="philosopher-jon"
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `entity` | str | **Required** | Type of entity to follow: `"userprofile"` or `"subwiki"` |
|
|
| `is_following` | bool | **Required** | `True` to follow, `False` to unfollow |
|
|
| `parent_slug` | str | **Required** | Slug of the entity to follow/unfollow |
|
|
|
|
**Returns:** dict - Job execution result
|
|
|
|
**Example - Follow a user:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.follow.follow import follow
|
|
|
|
API.wrapped(follow(
|
|
entity="userprofile",
|
|
is_following=True,
|
|
parent_slug="philosopher-jon"
|
|
))
|
|
```
|
|
|
|
**Example - Unfollow a branch:**
|
|
|
|
```python
|
|
API.wrapped(follow(
|
|
entity="subwiki",
|
|
is_following=False,
|
|
parent_slug="music"
|
|
))
|
|
```
|
|
|
|
---
|
|
|
|
### react()
|
|
|
|
React to a post or comment (like, heart, etc.). This single endpoint handles creating, updating, and deleting reactions — the logic is handled server-side.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.reaction.react import react
|
|
|
|
API.wrapped(react(
|
|
reaction_type="like",
|
|
parent_path="/music",
|
|
item_path="/music/my-post-slug"
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `reaction_type` | str | **Required** | Reaction type (e.g., `"like"`, `"heart"`, `"fire"`) |
|
|
| `parent_path` | str | `None` | Parent path (e.g., `"/music"`) |
|
|
| `item_path` | str | `None` | Item path (e.g., `"/music/my-post-slug"`) |
|
|
| `item_key` | dict | `None` | Dict with `pk` and `sk` keys |
|
|
|
|
**Returns:** dict - Job execution result
|
|
|
|
**Note:** You must provide either:
|
|
- Both `parent_path` and `item_path`, or
|
|
- The `item_key` dict with `pk` and `sk`
|
|
|
|
**Example - React by paths:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.reaction.react import react
|
|
|
|
API.wrapped(react(
|
|
reaction_type="like",
|
|
parent_path="/music",
|
|
item_path="/music/my-post-slug"
|
|
))
|
|
```
|
|
|
|
**Example - React by key:**
|
|
|
|
```python
|
|
API.wrapped(react(
|
|
reaction_type="heart",
|
|
item_key={
|
|
"pk": "post#my-post-slug",
|
|
"sk": "post#my-post-slug"
|
|
}
|
|
))
|
|
```
|
|
|
|
---
|
|
|
|
### trust()
|
|
|
|
Set trust level for a user profile.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.trust.trust import trust
|
|
|
|
API.wrapped(trust(
|
|
trustLevel="trusted",
|
|
userprofile_path="/userprofile/philosopher-jon"
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `trustLevel` | str | **Required** | Trust level: `"trusted"`, `"neutral"`, or `"distrusted"` |
|
|
| `userprofile_path` | str | **Required** | Path to the user profile (e.g., `"/userprofile/slug"`) |
|
|
|
|
**Returns:** dict - Job execution result
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.trust.trust import trust
|
|
|
|
API.wrapped(trust(
|
|
trustLevel="trusted",
|
|
userprofile_path="/userprofile/philosopher-jon"
|
|
))
|
|
```
|
|
|
|
---
|
|
|
|
### votecast()
|
|
|
|
Cast a vote on a post or comment.
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.vote.votecast import votecast
|
|
|
|
API.wrapped(votecast(
|
|
vote="up",
|
|
parent_path="/music",
|
|
item_path="/music/my-post-slug"
|
|
))
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `vote` | str | **Required** | Vote value (e.g., `"up"`, `"down"`) |
|
|
| `parent_path` | str | `None` | Parent path |
|
|
| `item_path` | str | `None` | Item path |
|
|
| `item_key` | dict | `None` | Dict with `pk` and `sk` keys |
|
|
|
|
**Returns:** dict - Job execution result
|
|
|
|
**Note:** You must provide either:
|
|
- Both `parent_path` and `item_path`, or
|
|
- The `item_key` dict with `pk` and `sk`
|
|
|
|
**Example - Vote by paths:**
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.vote.votecast import votecast
|
|
|
|
API.wrapped(votecast(
|
|
vote="up",
|
|
parent_path="/music",
|
|
item_path="/music/my-post-slug"
|
|
))
|
|
```
|
|
|
|
**Example - Vote by key:**
|
|
|
|
```python
|
|
API.wrapped(votecast(
|
|
vote="down",
|
|
item_key={
|
|
"pk": "post#my-post-slug",
|
|
"sk": "post#my-post-slug"
|
|
}
|
|
))
|
|
```
|
|
|
|
---
|
|
|
|
## Wrappers Best Practices
|
|
|
|
### 1. Provide Context in Parent Paths
|
|
|
|
**Good - Explicit paths:**
|
|
|
|
```python
|
|
API.wrapped(create_post(
|
|
"Content",
|
|
parent_path="/music/discussion" # Clear and specific
|
|
))
|
|
```
|
|
|
|
**Bad - Empty paths:**
|
|
|
|
```python
|
|
API.wrapped(create_post(
|
|
"Content",
|
|
parent_path="/" # Default root - less clear intention
|
|
))
|
|
```
|
|
|
|
### 2. Handle Phone Numbers in Content
|
|
|
|
When phone numbers appear in text, leave them as-is. The API wraps the input string, so `555-1234` stays `555-1234`. No HTML is added.
|
|
|
|
### 3. Path Normalization
|
|
|
|
Paths are used directly without extra normalization:
|
|
|
|
```python
|
|
# Use with leading slash
|
|
API.wrapped(create_post(
|
|
"Content",
|
|
parent_path="/music"
|
|
))
|
|
|
|
# Or without (both should work)
|
|
API.wrapped(create_post(
|
|
"Content",
|
|
parent_path="music"
|
|
))
|
|
```
|
|
|
|
### 4. Validate Parent Exists
|
|
|
|
It's good practice to verify the parent path exists:
|
|
|
|
```python
|
|
# Check if branch exists
|
|
branches = API.run_job('branch.listbyname')
|
|
|
|
if branches.get('Items'):
|
|
branch_slugs = [b.get('slug') for b in branches.get('Items', [])]
|
|
if 'music' in branch_slugs:
|
|
# Branch exists, proceed with post
|
|
API.wrapped(create_post(
|
|
"Content",
|
|
parent_path="/music"
|
|
))
|
|
else:
|
|
print("Branch 'music' does not exist")
|
|
else:
|
|
print("No branches found")
|
|
```
|
|
|
|
### 5. Handle Responses
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
|
|
|
response = API.wrapped(create_post(
|
|
"My post",
|
|
parent_path="/music"
|
|
))
|
|
|
|
# Check for success
|
|
if response and 'success' in response:
|
|
print("Post created successfully!")
|
|
print(f"Post ID: {response.get('pk')}")
|
|
else:
|
|
print("Failed to create post")
|
|
print(f"Error: {response.get('error')}")
|
|
```
|
|
|
|
### 6. Error Handling
|
|
|
|
```python
|
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
API.handle_token() # Ensure authenticated
|
|
API.wrapped(create_post(
|
|
"Post content",
|
|
parent_path="/music"
|
|
))
|
|
logger.info("Post created successfully")
|
|
except Exception as e:
|
|
logger.error(f"Failed to create post: {e}")
|
|
# Handle error - maybe retry, notify admin, etc.
|
|
```
|
|
|
|
## Wrapper vs Job
|
|
|
|
| Feature | Wrappers | Jobs |
|
|
|---------|----------|------|
|
|
| **Simplicity** | ⭐⭐⭐⭐⭐ | ⭐⭐ |
|
|
| **Flexibility** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
|
| **Default Values** | ✅ Yes | ❌ No |
|
|
| **Parameter Validation** | ✅ Yes | ❌ No |
|
|
| **Common Operations** | ✅ Many | ❌ None |
|
|
| **Custom Operations** | ❌ No | ✅ Yes |
|
|
| **Learning Curve** | Low | High |
|
|
|
|
### Replacement Examples
|
|
|
|
**Example 1: Create Post**
|
|
|
|
```python
|
|
# Wrapper - Simple
|
|
API.wrapped(create_post(
|
|
"Content",
|
|
parent_path="/music"
|
|
))
|
|
|
|
# Job - More complex
|
|
API.run_job('post.create', {
|
|
"postText": "Content",
|
|
"parent": {
|
|
"pk": "encode(parent_path)",
|
|
"sk": "encode(parent_path)"
|
|
}
|
|
})
|
|
```
|
|
|
|
**Example 2: Update Post**
|
|
|
|
```python
|
|
# Wrapper
|
|
API.wrapped(update_post(
|
|
post_text="New content",
|
|
parent_path="/music"
|
|
))
|
|
|
|
# Job
|
|
API.run_job('post.update', {
|
|
"pk": "post-id",
|
|
"sk": "post-id",
|
|
"newPostText": "New content"
|
|
})
|
|
```
|
|
|
|
**Example 3: Create Comment**
|
|
|
|
```python
|
|
# Wrapper
|
|
API.wrapped(create_comment(
|
|
"My comment",
|
|
post_slug="post-id",
|
|
parent_path="/branch"
|
|
))
|
|
|
|
# Job
|
|
API.run_job('comment.create', {
|
|
"commentText": "My comment",
|
|
"parent": {
|
|
"pk": "post-id",
|
|
"sk": "post-id"
|
|
}
|
|
})
|
|
```
|
|
|
|
### When to Use Each
|
|
|
|
**Use Wrappers When:**
|
|
- Common operation (create/update post/comment)
|
|
- Multiple optional parameters
|
|
- Want concise, readable code
|
|
- Acceptable default behavior
|
|
|
|
**Use Jobs When:**
|
|
- Rarely used operation
|
|
- Very specific parameter combinations
|
|
- Custom job names unsupported by wrappers
|
|
- Need maximum flexibility
|
|
|
|
## Creating Custom Wrappers
|
|
|
|
You can create your own wrappers for repeated operations:
|
|
|
|
```python
|
|
# Custom post wrapper
|
|
def create_in_branch(API, branch: str, content: str, create_card: bool = False):
|
|
"""
|
|
Helper wrapper for creating posts in specific branches.
|
|
|
|
Args:
|
|
API: The APIClient instance
|
|
branch: Branch name (e.g., "music", "science")
|
|
content: Post content
|
|
create_card: Whether to create a card URL
|
|
|
|
Returns:
|
|
dict: API response
|
|
"""
|
|
card_url = "https://example.com/card" if create_card else None
|
|
|
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
|
|
|
return API.wrapped(create_post(
|
|
content,
|
|
parent_path=f"/{branch}",
|
|
card_url=card_url
|
|
))
|
|
|
|
# Usage
|
|
API.handle_token()
|
|
result = create_in_branch(API, "music", "New music discussion")
|
|
|
|
# Or with card
|
|
result = create_in_branch(API, "science", "Research paper abstract", create_card=True)
|
|
```
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Wrappers provide a convenient, safe way to perform common operations with the TrustCafé API. For most use cases, wrappers reduce boilerplate and prevent configuration errors. However, jobs offer greater flexibility when standard wrappers don't meet your needs.
|
|
|
|
**Choose wisely:**
|
|
- Wrappers for standard operations and simplicity
|
|
- Jobs for custom operations and maximum control
|