doc: audit pass — fix env= bug, params, pagination, missing wrappers, broken examples
- 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
This commit is contained in:
parent
c8611a7b88
commit
a223bcb27a
9 changed files with 552 additions and 247 deletions
101
CODE_BUGS.md
Normal file
101
CODE_BUGS.md
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
# Code Bugs Found During Documentation Audit
|
||||||
|
|
||||||
|
This file documents bugs discovered in the source code during the documentation audit on April 18, 2026. These are **not** documentation errors — they are issues in the code itself that affect runtime behavior.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. `trust.listbyusersinit` — Function Name Mismatch
|
||||||
|
|
||||||
|
**Severity:** High — causes runtime crash
|
||||||
|
|
||||||
|
**File:** `src/trustcafeapiwrapper/jobs/trust/listbyusersinit.py`
|
||||||
|
|
||||||
|
**Problem:** The file is named `listbyusersinit.py`, but the function inside is named `listbyuserinit()`. Additionally, `src/trustcafeapiwrapper/jobs/trust/__init__.py` imports `listbyuserinit` (matching the function name), not `listbyusersinit` (matching the file name).
|
||||||
|
|
||||||
|
**Impact:** Calling `API.run_job('trust.listbyusersinit')` resolves to the *module* object (because Python can import submodules as attributes), not the function. This causes `TypeError: 'module' object is not callable`.
|
||||||
|
|
||||||
|
**Working alternative:** `API.run_job('trust.listbyuserinit', user_id)` — this resolves to the actual function and works correctly.
|
||||||
|
|
||||||
|
**Evidence:**
|
||||||
|
```python
|
||||||
|
API.run_job('trust.listbyusersinit')
|
||||||
|
# TypeError: 'module' object is not callable
|
||||||
|
|
||||||
|
API.run_job('trust.listbyuserinit', 'user123')
|
||||||
|
# Resolves correctly, makes API call (will fail auth without real credentials, but function resolution works)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix options:**
|
||||||
|
- Rename the function from `listbyuserinit` to `listbyusersinit` in `listbyusersinit.py` and update `trust/__init__.py`
|
||||||
|
- OR rename the file from `listbyusersinit.py` to `listbyuserinit.py`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. `APIClient.wrapped()` — Docstring Mismatch
|
||||||
|
|
||||||
|
**Severity:** Low — code works correctly, docstring is wrong
|
||||||
|
|
||||||
|
**File:** `src/trustcafeapiwrapper/apiclient.py`, method `wrapped()`
|
||||||
|
|
||||||
|
**Problem:** The docstring says the method expects `'job'` and `'payload'` keys:
|
||||||
|
```
|
||||||
|
A dictionary with 'job' (string) and 'payload' (dict) keys.
|
||||||
|
```
|
||||||
|
But the actual code reads `job_function`:
|
||||||
|
```python
|
||||||
|
return self.run_job(wrapped_data.get("job_function"), wrapped_data.get("payload", {}))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** No runtime impact — all wrapper functions return `{"job_function": ..., "payload": ...}` which matches what `wrapped()` reads. Only the docstring is misleading.
|
||||||
|
|
||||||
|
**Fix:** Update docstring from `'job'` to `'job_function'`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. `env=` Constructor Parameter Silently Ignored
|
||||||
|
|
||||||
|
**Severity:** High — silent wrong-environment bug
|
||||||
|
|
||||||
|
**File:** `src/trustcafeapiwrapper/apiclient.py`, class `APIClient`
|
||||||
|
|
||||||
|
**Problem:** `APIClient` inherits from Pydantic's `BaseModel`. The model defines `environment: str = "alpha"`, but there is no field named `env`. Because Pydantic silently ignores unknown fields by default, passing `env="production"` is **silently discarded** and the environment stays `"alpha"`.
|
||||||
|
|
||||||
|
**Impact:** Any code using `APIClient(client_id=..., client_secret=..., env="production")` will silently run against the alpha environment instead of production. No error, no warning.
|
||||||
|
|
||||||
|
**Evidence:**
|
||||||
|
```python
|
||||||
|
API = APIClient(client_id='test', client_secret='test', env='production')
|
||||||
|
print(API.environment) # Prints "alpha" — NOT "production"
|
||||||
|
|
||||||
|
API = APIClient(client_id='test', client_secret='test', environment='production')
|
||||||
|
print(API.environment) # Prints "production" — correct
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix options:**
|
||||||
|
- Add a model validator that raises an error on unknown fields: `model_config = ConfigDict(extra='forbid')`
|
||||||
|
- OR add `env` as an alias for `environment`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Missing `__version__` Attribute
|
||||||
|
|
||||||
|
**Severity:** Low — not a runtime bug, but a packaging convention
|
||||||
|
|
||||||
|
**File:** `src/trustcafeapiwrapper/__init__.py`
|
||||||
|
|
||||||
|
**Problem:** The module does not expose `__version__`. The `__init__.py` only contains:
|
||||||
|
```python
|
||||||
|
from .apiclient import APIClient
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Users cannot programmatically check the installed version via `trustcafeapiwrapper.__version__`. This is a standard Python packaging convention.
|
||||||
|
|
||||||
|
**Fix:** Add to `__init__.py`:
|
||||||
|
```python
|
||||||
|
from importlib.metadata import version as _get_version
|
||||||
|
__version__ = _get_version("trustcafeapiwrapper")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*These bugs were found during a documentation accuracy audit. The documentation has been updated to reflect actual code behavior (e.g., using `environment=` instead of `env=`, documenting `trust.listbyuserinit` as the working job name).*
|
||||||
30
README.md
30
README.md
|
|
@ -64,13 +64,13 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="alpha", # Options: "alpha" or "production"
|
environment="alpha", # Options: "alpha" or "production"
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
# Authenticate and get user profile
|
# Authenticate and get user profile
|
||||||
API.handle_token()
|
API.handle_token()
|
||||||
profile = API.run_job('userprofile.get', "your-username")
|
profile = API.run_job('userprofile.get', "your-user-slug")
|
||||||
print(profile)
|
print(profile)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@ def saveMyToken(token_data):
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id=os.getenv("client_id"),
|
client_id=os.getenv("client_id"),
|
||||||
client_secret=os.getenv("client_secret"),
|
client_secret=os.getenv("client_secret"),
|
||||||
env="production",
|
environment="production",
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -144,7 +144,7 @@ The wrapper supports two environments:
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id="your-client-id",
|
client_id="your-client-id",
|
||||||
client_secret="your-client-secret",
|
client_secret="your-client-secret",
|
||||||
env="alpha",
|
environment="alpha",
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -152,7 +152,7 @@ API = APIClient(
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id="your-client-id",
|
client_id="your-client-id",
|
||||||
client_secret="your-client-secret",
|
client_secret="your-client-secret",
|
||||||
env="production",
|
environment="production",
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -200,8 +200,8 @@ updated_post = API.run_job('post.update', {
|
||||||
"newPostText": "Updated text"
|
"newPostText": "Updated text"
|
||||||
})
|
})
|
||||||
|
|
||||||
# Delete a post
|
# List removed posts
|
||||||
deleted = API.run_job('post.listremoved', "post-id")
|
removed = API.run_job('post.listremoved')
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Comment Operations
|
#### Comment Operations
|
||||||
|
|
@ -224,7 +224,7 @@ comments = API.run_job('comment.listtbypostid', "post-id")
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Get user profile
|
# Get user profile
|
||||||
profile = API.run_job('userprofile.get', "username")
|
profile = API.run_job('userprofile.get', "user-slug")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Follow Operations
|
#### Follow Operations
|
||||||
|
|
@ -232,7 +232,7 @@ profile = API.run_job('userprofile.get', "username")
|
||||||
```python
|
```python
|
||||||
# Follow a user
|
# Follow a user
|
||||||
followed = API.run_job('follow.follow', {
|
followed = API.run_job('follow.follow', {
|
||||||
"isFollowing": true,
|
"isFollowing": True,
|
||||||
"parent": {
|
"parent": {
|
||||||
"pk": "userprofile#username",
|
"pk": "userprofile#username",
|
||||||
"sk": "userprofile#username"
|
"sk": "userprofile#username"
|
||||||
|
|
@ -427,7 +427,7 @@ Enable debug mode to see all API requests and responses:
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id=os.getenv("client_id"),
|
client_id=os.getenv("client_id"),
|
||||||
client_secret=os.getenv("client_secret"),
|
client_secret=os.getenv("client_secret"),
|
||||||
env="production",
|
environment="production",
|
||||||
debug=True # Enable debug mode
|
debug=True # Enable debug mode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -447,7 +447,7 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="alpha",
|
environment="alpha",
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -475,12 +475,12 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="production"
|
environment="production"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Follow a user
|
# Follow a user
|
||||||
follow = API.run_job('follow.follow', {
|
follow = API.run_job('follow.follow', {
|
||||||
"isFollowing": true,
|
"isFollowing": True,
|
||||||
"parent": {
|
"parent": {
|
||||||
"pk": "userprofile#philosopher-jon",
|
"pk": "userprofile#philosopher-jon",
|
||||||
"sk": "userprofile#philosopher-jon"
|
"sk": "userprofile#philosopher-jon"
|
||||||
|
|
@ -504,7 +504,7 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="production"
|
environment="production"
|
||||||
)
|
)
|
||||||
|
|
||||||
API.handle_token()
|
API.handle_token()
|
||||||
|
|
@ -527,7 +527,7 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="production"
|
environment="production"
|
||||||
)
|
)
|
||||||
|
|
||||||
API.handle_token()
|
API.handle_token()
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="alpha", # or "production"
|
environment="alpha", # or "production"
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -159,7 +159,8 @@ Lists all posts.
|
||||||
posts = API.run_job('post.listall')
|
posts = API.run_job('post.listall')
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:** None
|
**Parameters:**
|
||||||
|
- `lastEvaluatedKey` (dict, optional): Pagination key for next page
|
||||||
|
|
||||||
**Returns:** dict - List of all posts
|
**Returns:** dict - List of all posts
|
||||||
|
|
||||||
|
|
@ -173,13 +174,14 @@ print(f"Total posts: {len(all_posts.get('Items', []))}")
|
||||||
|
|
||||||
### post.listpublic()
|
### post.listpublic()
|
||||||
|
|
||||||
Lists public posts only.
|
Lists public posts only. This endpoint does not require authentication.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
public_posts = API.run_job('post.listpublic')
|
public_posts = API.run_job('post.listpublic')
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:** None
|
**Parameters:**
|
||||||
|
- `lastEvaluatedKey` (dict, optional): Pagination key for next page
|
||||||
|
|
||||||
**Returns:** dict - List of public posts
|
**Returns:** dict - List of public posts
|
||||||
|
|
||||||
|
|
@ -197,11 +199,12 @@ for post in public_posts.get('Items', []):
|
||||||
Lists posts in a specific branch.
|
Lists posts in a specific branch.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
branch_posts = API.run_job('post.listbybranch', branch_name)
|
branch_posts = API.run_job('post.listbybranch', branch_slug)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `branchName` (str): The branch identifier
|
- `branch_slug` (str): The branch/subwiki slug identifier
|
||||||
|
- `lastEvaluatedKey` (dict, optional): Pagination key for next page
|
||||||
|
|
||||||
**Returns:** dict - List of posts in the branch
|
**Returns:** dict - List of posts in the branch
|
||||||
|
|
||||||
|
|
@ -217,11 +220,12 @@ music_posts = API.run_job('post.listbybranch', "music")
|
||||||
Lists posts by a specific user profile.
|
Lists posts by a specific user profile.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
user_posts = API.run_job('post.listbyuserprofile', username)
|
user_posts = API.run_job('post.listbyuserprofile', user_slug)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `username` (str): The username of the user
|
- `user_slug` (str): The user profile slug
|
||||||
|
- `lastEvaluatedKey` (dict, optional): Pagination key for next page
|
||||||
|
|
||||||
**Returns:** dict - List of posts by user
|
**Returns:** dict - List of posts by user
|
||||||
|
|
||||||
|
|
@ -237,17 +241,19 @@ journals = API.run_job('post.listbyuserprofile', "philosopher-jon")
|
||||||
Lists removed/deleted posts.
|
Lists removed/deleted posts.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
removed = API.run_job('post.listremoved', post_id)
|
removed = API.run_job('post.listremoved')
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `postId` (str): The post identifier
|
- `lastEvaluatedKey` (dict, optional): Pagination key for next page
|
||||||
|
|
||||||
**Returns:** dict - Removed post data
|
**Returns:** dict - List of removed posts
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
removed_post = API.run_job('post.listremoved', "deleted-post-id")
|
removed_posts = API.run_job('post.listremoved')
|
||||||
|
for post in removed_posts.get('Items', []):
|
||||||
|
print(post.get('pk'))
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -295,7 +301,7 @@ comments = API.run_job('comment.listtbypostid', post_id)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `postId` (str): The post ID
|
- `post_id` (str): The post ID
|
||||||
|
|
||||||
**Returns:** dict - List of comments
|
**Returns:** dict - List of comments
|
||||||
|
|
||||||
|
|
@ -360,7 +366,7 @@ result = API.run_job('follow.follow', payload)
|
||||||
```python
|
```python
|
||||||
# Follow a user
|
# Follow a user
|
||||||
followed = API.run_job('follow.follow', {
|
followed = API.run_job('follow.follow', {
|
||||||
"isFollowing": true,
|
"isFollowing": True,
|
||||||
"parent": {
|
"parent": {
|
||||||
"pk": "userprofile#philosopher-jon",
|
"pk": "userprofile#philosopher-jon",
|
||||||
"sk": "userprofile#philosopher-jon"
|
"sk": "userprofile#philosopher-jon"
|
||||||
|
|
@ -368,9 +374,9 @@ followed = API.run_job('follow.follow', {
|
||||||
"followType": "userprofile",
|
"followType": "userprofile",
|
||||||
"parentSlug": "philosopher-jon",
|
"parentSlug": "philosopher-jon",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"notification": true,
|
"notification": True,
|
||||||
"emailNew": false,
|
"emailNew": False,
|
||||||
"emailDigest": true
|
"emailDigest": True
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
@ -796,20 +802,20 @@ For large result sets, results may include pagination:
|
||||||
```python
|
```python
|
||||||
def get_all_posts():
|
def get_all_posts():
|
||||||
posts = []
|
posts = []
|
||||||
paginator = None
|
last_key = None
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
response = API.run_job('post.listpublic', params)
|
if last_key:
|
||||||
|
response = API.run_job('post.listpublic', last_key)
|
||||||
|
else:
|
||||||
|
response = API.run_job('post.listpublic')
|
||||||
posts.extend(response.get('Items', []))
|
posts.extend(response.get('Items', []))
|
||||||
|
|
||||||
has_more = 'LastEvaluatedKey' in response
|
has_more = 'LastEvaluatedKey' in response
|
||||||
if not has_more:
|
if not has_more:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Set params for next page
|
last_key = response['LastEvaluatedKey']
|
||||||
params = {
|
|
||||||
'ExclusiveStartKey': response['LastEvaluatedKey']
|
|
||||||
}
|
|
||||||
|
|
||||||
return posts
|
return posts
|
||||||
```
|
```
|
||||||
|
|
@ -877,6 +883,6 @@ Implement rate limiting for production use (see main README for example).
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
- [Wrappers Guide](wrappers.md) - High-level wrappers for common tasks
|
- [Wrappers Guide](WRAPPERS.md) - High-level wrappers for common tasks
|
||||||
- [Custom Requests Guide](custom_requests.md) - Making advanced API calls
|
- [Custom Requests Guide](CUSTOM_REQUESTS.md) - Making advanced API calls
|
||||||
- [Troubleshooting Guide](troubleshooting.md) - Common issues and solutions
|
- [Troubleshooting Guide](TROUBLESHOOTING.md) - Common issues and solutions
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ import os
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("CLIENT_ID"),
|
client_id=os.getenv("CLIENT_ID"),
|
||||||
client_secret=os.getenv("CLIENT_SECRET"),
|
client_secret=os.getenv("CLIENT_SECRET"),
|
||||||
env="alpha",
|
environment="alpha",
|
||||||
debug=True
|
debug=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -172,17 +172,16 @@ response = API.make_request(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual token injection (advanced):
|
### Manual token handling (advanced):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Sometimes you may need to bypass the token management
|
# If you need to bypass token management, set the access_token directly on the API instance
|
||||||
|
API.access_token = "your-token-manually-set"
|
||||||
|
|
||||||
response = API.make_request(
|
response = API.make_request(
|
||||||
"GET",
|
"GET",
|
||||||
"content",
|
"content",
|
||||||
"post/some-path",
|
"post/some-path"
|
||||||
headers={
|
|
||||||
"Authorization": "Bearer your-token-manually-set"
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -194,30 +193,25 @@ TrustCafé responses may include pagination for large result sets:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_all_posts(limit=100):
|
def get_all_posts(limit=100):
|
||||||
"""Fetch all posts with pagination"""
|
"""Fetch all posts with pagination using make_request directly."""
|
||||||
|
|
||||||
def fetch_page(start_key=None):
|
def fetch_page(last_evaluated_key=None):
|
||||||
"""Fetch a single page of posts"""
|
"""Fetch a single page of posts"""
|
||||||
params = {"Limit": limit}
|
|
||||||
|
|
||||||
if start_key:
|
|
||||||
params["ExclusiveStartKey"] = start_key
|
|
||||||
|
|
||||||
response = API.make_request(
|
response = API.make_request(
|
||||||
"GET",
|
"GET",
|
||||||
"content",
|
"content",
|
||||||
"post/listall",
|
"post",
|
||||||
query_params=params,
|
query_params=last_evaluated_key,
|
||||||
authenticate=True
|
authenticate=True
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
all_posts = []
|
all_posts = []
|
||||||
start_key = None
|
last_key = None
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
page = fetch_page(start_key)
|
page = fetch_page(last_key)
|
||||||
|
|
||||||
items = page.get('Items', [])
|
items = page.get('Items', [])
|
||||||
all_posts.extend(items)
|
all_posts.extend(items)
|
||||||
|
|
@ -227,15 +221,15 @@ def get_all_posts(limit=100):
|
||||||
if not has_more or len(items) == 0:
|
if not has_more or len(items) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Set start key for next page
|
# Pass the LastEvaluatedKey directly as query_params for next page
|
||||||
start_key = page['LastEvaluatedKey']
|
last_key = page['LastEvaluatedKey']
|
||||||
|
|
||||||
return all_posts
|
return all_posts
|
||||||
|
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
API.handle_token()
|
API.handle_token()
|
||||||
all_posts = get_all_posts(limit=50)
|
all_posts = get_all_posts()
|
||||||
print(f"Total posts: {len(all_posts)}")
|
print(f"Total posts: {len(all_posts)}")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -761,7 +755,7 @@ def conditional_update_post(post_id, updates, condition=None):
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
- [API Reference](api_reference.md) - Complete list of jobs
|
- [API Reference](API_REFERENCE.md) - Complete list of jobs
|
||||||
- [Wrappers Guide](wrappers.md) - High-level wrappers for common operations
|
- [Wrappers Guide](WRAPPERS.md) - High-level wrappers for common operations
|
||||||
- [Examples](../README.md#examples) - Real-world usage examples
|
- [Examples](../README.md#examples) - Real-world usage examples
|
||||||
- [Troubleshooting](troubleshooting.md) - Common issues and solutions
|
- [Troubleshooting](TROUBLESHOOTING.md) - Common issues and solutions
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,10 @@ uv add trustcafeapiwrapper
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import trustcafeapiwrapper
|
import trustcafeapiwrapper
|
||||||
print(trustcafeapiwrapper.__version__) # Should print the version
|
|
||||||
|
# Verify the module imported successfully
|
||||||
|
from trustcafeapiwrapper import APIClient
|
||||||
|
print("trustcafeapiwrapper installed successfully")
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Credentials Setup
|
## API Credentials Setup
|
||||||
|
|
@ -120,7 +123,7 @@ The TrustCafé API wrapper supports two environments:
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="alpha" # Alpha environment
|
environment="alpha" # Alpha environment
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -134,7 +137,7 @@ API = APIClient(
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="production" # Production environment
|
environment="production" # Production environment
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -142,7 +145,7 @@ API = APIClient(
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Initialize with alpha
|
# Initialize with alpha
|
||||||
API = APIClient(client_id="id", client_secret="secret", env="alpha")
|
API = APIClient(client_id="id", client_secret="secret", environment="alpha")
|
||||||
|
|
||||||
# Later, switch to production
|
# Later, switch to production
|
||||||
API.set_environment("production")
|
API.set_environment("production")
|
||||||
|
|
@ -162,7 +165,7 @@ load_dotenv()
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
client_id=os.getenv("TRUSTCAFE_CLIENT_ID"),
|
||||||
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
client_secret=os.getenv("TRUSTCAFE_CLIENT_SECRET"),
|
||||||
env="alpha", # or "production"
|
environment="alpha", # or "production"
|
||||||
debug=True # Set to True to see request/response details
|
debug=True # Set to True to see request/response details
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -307,7 +310,7 @@ Always test in alpha before production:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Test with alpha first
|
# Test with alpha first
|
||||||
API = APIClient(client_id="test-id", client_secret="test-secret", env="alpha")
|
API = APIClient(client_id="test-id", client_secret="test-secret", environment="alpha")
|
||||||
|
|
||||||
# Verify token works
|
# Verify token works
|
||||||
results = API.handle_token()
|
results = API.handle_token()
|
||||||
|
|
@ -317,7 +320,7 @@ print("Alpha environment works!")
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id=os.getenv("PROD_CLIENT_ID"),
|
client_id=os.getenv("PROD_CLIENT_ID"),
|
||||||
client_secret=os.getenv("PROD_CLIENT_SECRET"),
|
client_secret=os.getenv("PROD_CLIENT_SECRET"),
|
||||||
env="production"
|
environment="production"
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -369,7 +372,7 @@ Use debug mode during development:
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id="your-id",
|
client_id="your-id",
|
||||||
client_secret="your-secret",
|
client_secret="your-secret",
|
||||||
env="internal",
|
environment="alpha", # "alpha" or "production"
|
||||||
debug=True # Prints request/response details
|
debug=True # Prints request/response details
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
@ -454,16 +457,16 @@ LOG_LEVEL=INFO
|
||||||
Now that you're set up:
|
Now that you're set up:
|
||||||
|
|
||||||
1. **Read the API Reference**: Learn about all available jobs and wrappers
|
1. **Read the API Reference**: Learn about all available jobs and wrappers
|
||||||
- [API Reference](api_reference.md)
|
- [API Reference](API_REFERENCE.md)
|
||||||
|
|
||||||
2. **Explore Wrappers**: Try the high-level wrappers for common tasks
|
2. **Explore Wrappers**: Try the high-level wrappers for common tasks
|
||||||
- [Wrappers Guide](wrappers.md)
|
- [Wrappers Guide](WRAPPERS.md)
|
||||||
|
|
||||||
3. **Make Custom Requests**: Learn to make advanced API calls manually
|
3. **Make Custom Requests**: Learn to make advanced API calls manually
|
||||||
- [Custom Requests Guide](custom_requests.md)
|
- [Custom Requests Guide](CUSTOM_REQUESTS.md)
|
||||||
|
|
||||||
4. **Handle Errors**: Learn about common errors and how to handle them
|
4. **Handle Errors**: Learn about common errors and how to handle them
|
||||||
- [Troubleshooting Guide](troubleshooting.md)
|
- [Troubleshooting Guide](TROUBLESHOOTING.md)
|
||||||
|
|
||||||
5. **Contribute**: Help complete the wrapper with additional jobs
|
5. **Contribute**: Help complete the wrapper with additional jobs
|
||||||
- [Development Guide](development.md)
|
- [Development Guide](../development.md)
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ Complete documentation for the TrustCafé API wrapper.
|
||||||
- Overview of wrapper system
|
- Overview of wrapper system
|
||||||
- Post wrapper documentation (create_post, update_post)
|
- Post wrapper documentation (create_post, update_post)
|
||||||
- Comment wrapper documentation (create_comment)
|
- Comment wrapper documentation (create_comment)
|
||||||
|
- Interaction wrappers (follow, react, trust, votecast)
|
||||||
- Wrapper best practices
|
- Wrapper best practices
|
||||||
- Wrapper vs Job comparison
|
- Wrapper vs Job comparison
|
||||||
- Creating custom wrappers
|
- Creating custom wrappers
|
||||||
|
|
@ -126,16 +127,16 @@ If you can't find the answer you're looking for:
|
||||||
|
|
||||||
Document version updates should be listed here.
|
Document version updates should be listed here.
|
||||||
|
|
||||||
### v0.2.0 (Current)
|
### v0.2.0 (Current Documentation)
|
||||||
- Complete rewrite and enhancement of all documentation
|
- Complete rewrite and enhancement of all documentation
|
||||||
- Added full API reference
|
- Added full API reference
|
||||||
- Added wrappers guide
|
- Added wrappers guide (including follow, react, trust, votecast)
|
||||||
- Added custom requests guide
|
- Added custom requests guide
|
||||||
- Added detailed troubleshooting section
|
- Added detailed troubleshooting section
|
||||||
- Enhanced development documentation
|
- Enhanced development documentation
|
||||||
- Improved README.md structure and examples
|
- Improved README.md structure and examples
|
||||||
|
|
||||||
### v0.1.0.13
|
### v0.1.0.13 (Package Version / Initial Release)
|
||||||
- Initial release with basic documentation
|
- Initial release with basic documentation
|
||||||
- Minimum set of jobs and wrappers
|
- Minimum set of jobs and wrappers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ FileNotFoundError: Token data file 'token_data_alpha.json' not found
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. API `<environment>_handle_token` automatically creates file on first use
|
1. API `handle_token` automatically creates file on first use
|
||||||
|
|
||||||
2. Ensure working directory is writable
|
2. Ensure working directory is writable
|
||||||
|
|
||||||
|
|
@ -346,7 +346,7 @@ ValueError: Invalid parameter or data format
|
||||||
|
|
||||||
4. Use debug mode to see request:
|
4. Use debug mode to see request:
|
||||||
```python
|
```python
|
||||||
API = APIClient(debug=True)
|
API = APIClient(client_id="your-id", client_secret="your-secret", debug=True)
|
||||||
|
|
||||||
# Now you'll see the exact data being sent
|
# Now you'll see the exact data being sent
|
||||||
API.run_job('post.create', data)
|
API.run_job('post.create', data)
|
||||||
|
|
@ -389,7 +389,7 @@ FileNotFoundError: Endpoint not found
|
||||||
|
|
||||||
4. Use debug mode to see exact path being sent:
|
4. Use debug mode to see exact path being sent:
|
||||||
```python
|
```python
|
||||||
API = APIClient(debug=True)
|
API = APIClient(client_id="your-id", client_secret="your-secret", debug=True)
|
||||||
API.run_job('post.create', data) # See exact request path
|
API.run_job('post.create', data) # See exact request path
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -493,7 +493,7 @@ ValueError: Environment 'staging' is not valid. Must be one of: ['alpha', 'produ
|
||||||
API_prod = APIClient(
|
API_prod = APIClient(
|
||||||
client_id="prod-id",
|
client_id="prod-id",
|
||||||
client_secret="prod-secret",
|
client_secret="prod-secret",
|
||||||
env="production"
|
environment="production"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Old API still has old environment
|
# Old API still has old environment
|
||||||
|
|
@ -663,7 +663,7 @@ requests.exceptions.Timeout: Request timed out
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id="your-id",
|
client_id="your-id",
|
||||||
client_secret="your-secret",
|
client_secret="your-secret",
|
||||||
env="alpha",
|
environment="alpha",
|
||||||
debug=True # Enables verbose logging
|
debug=True # Enables verbose logging
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
214
docs/WRAPPERS.md
214
docs/WRAPPERS.md
|
|
@ -7,6 +7,7 @@ This guide covers the high-level wrapper functions provided by the TrustCafé AP
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
- [Post Wrappers](#post-wrappers)
|
- [Post Wrappers](#post-wrappers)
|
||||||
- [Comment Wrappers](#comment-wrappers)
|
- [Comment Wrappers](#comment-wrappers)
|
||||||
|
- [Interaction Wrappers](#interaction-wrappers)
|
||||||
- [Wrappers Best Practices](#wrappers-best-practices)
|
- [Wrappers Best Practices](#wrappers-best-practices)
|
||||||
- [Wrapper vs Job](#wrapper-vs-job)
|
- [Wrapper vs Job](#wrapper-vs-job)
|
||||||
|
|
||||||
|
|
@ -308,6 +309,201 @@ API.wrapped(create_comment(
|
||||||
))
|
))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 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
|
## Wrappers Best Practices
|
||||||
|
|
||||||
### 1. Provide Context in Parent Paths
|
### 1. Provide Context in Parent Paths
|
||||||
|
|
@ -358,16 +554,20 @@ It's good practice to verify the parent path exists:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Check if branch exists
|
# Check if branch exists
|
||||||
branches = API.run_job('branch.listbyname', "music")
|
branches = API.run_job('branch.listbyname')
|
||||||
|
|
||||||
if branches.get('Items'):
|
if branches.get('Items'):
|
||||||
# Branch exists, proceed with post
|
branch_slugs = [b.get('slug') for b in branches.get('Items', [])]
|
||||||
API.wrapped(create_post(
|
if 'music' in branch_slugs:
|
||||||
"Content",
|
# Branch exists, proceed with post
|
||||||
parent_path="/music"
|
API.wrapped(create_post(
|
||||||
))
|
"Content",
|
||||||
|
parent_path="/music"
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
print("Branch 'music' does not exist")
|
||||||
else:
|
else:
|
||||||
print("Branch 'music' does not exist")
|
print("No branches found")
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. Handle Responses
|
### 5. Handle Responses
|
||||||
|
|
|
||||||
308
documentation.md
308
documentation.md
|
|
@ -1,155 +1,155 @@
|
||||||
# Basic usage (without an .env)
|
# Basic usage (without an .env)
|
||||||
## Setup
|
## Setup
|
||||||
Here's a very basic example of setting up:
|
Here's a very basic example of setting up:
|
||||||
```python
|
```python
|
||||||
import trustcafeapiwrapper
|
import trustcafeapiwrapper
|
||||||
|
|
||||||
# Setup the API Client
|
# Setup the API Client
|
||||||
API = trustcafeapiwrapper.APIClient(
|
API = trustcafeapiwrapper.APIClient(
|
||||||
client_id="YOUR_CLIENT_ID",
|
client_id="YOUR_CLIENT_ID",
|
||||||
client_secret="YOUR_CLIENT_SECRET",
|
client_secret="YOUR_CLIENT_SECRET",
|
||||||
env="alpha" # alpha | production.
|
environment="alpha", # alpha | production.
|
||||||
debug=False
|
debug=False
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
or with .env
|
or with .env
|
||||||
```python
|
```python
|
||||||
import trustcafeapiwrapper, os
|
import trustcafeapiwrapper, os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
API = APIClient(
|
API = APIClient(
|
||||||
client_id=os.getenv("client_id"),
|
client_id=os.getenv("client_id"),
|
||||||
client_secret=os.getenv("client_secret"),
|
client_secret=os.getenv("client_secret"),
|
||||||
env="alpha", # alpha | production.
|
environment="alpha", # alpha | production.
|
||||||
debug=False,
|
debug=False,
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
## Handle token (easy way)
|
## Handle token (easy way)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
API.handle_token()
|
API.handle_token()
|
||||||
```
|
```
|
||||||
## Handling the token yourself
|
## Handling the token yourself
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
||||||
def getMyToken():
|
def getMyToken():
|
||||||
# get the token from your personal store
|
# get the token from your personal store
|
||||||
# initially this will be None
|
# initially this will be None
|
||||||
return token_data
|
return token_data
|
||||||
|
|
||||||
def saveMyToken():
|
def saveMyToken():
|
||||||
# save your token to your personal store
|
# save your token to your personal store
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Use the old token or None if we haven't logged in ever from here
|
# Use the old token or None if we haven't logged in ever from here
|
||||||
API.set_token(getMyToken())
|
API.set_token(getMyToken())
|
||||||
# Get a new one if we don't have one or if the existing one is expired
|
# Get a new one if we don't have one or if the existing one is expired
|
||||||
if not API.is_token_valid():
|
if not API.is_token_valid():
|
||||||
saveMyToken(API.sign_in())
|
saveMyToken(API.sign_in())
|
||||||
```
|
```
|
||||||
|
|
||||||
## Use a wrapper
|
## Use a wrapper
|
||||||
Wrappers make it as simple as possible to perform an action.
|
Wrappers make it as simple as possible to perform an action.
|
||||||
|
|
||||||
A wrapper will come with a job and a payload ready to be passed to the `wrapped` function.
|
A wrapper will come with a job and a payload ready to be passed to the `wrapped` function.
|
||||||
|
|
||||||
eg. Use the `create_post` wrapper
|
eg. Use the `create_post` wrapper
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
from trustcafeapiwrapper.wrappers.post.create_post import create_post
|
||||||
|
|
||||||
API.wrapped(create_post(
|
API.wrapped(create_post(
|
||||||
"This is a test post created via the create_post wrapper function.",
|
"This is a test post created via the create_post wrapper function.",
|
||||||
))
|
))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**_NOTE:_** There are not as many wrappers as jobs because fetching is simpler. More will be added though to make it consistent.
|
**_NOTE:_** There are not as many wrappers as jobs because fetching is simpler. More will be added though to make it consistent.
|
||||||
|
|
||||||
|
|
||||||
## Make a request via `job`
|
## Make a request via `job`
|
||||||
Jobs make the requests to the API. They have the endpoint and path setup already, we just pass the payload. If you want to avoid making your own payload, use a `wrapper`.
|
Jobs make the requests to the API. They have the endpoint and path setup already, we just pass the payload. If you want to avoid making your own payload, use a `wrapper`.
|
||||||
|
|
||||||
Use the job for getting public posts.
|
Use the job for getting public posts.
|
||||||
|
|
||||||
Now you don't need to worry about which API
|
Now you don't need to worry about which API
|
||||||
```python
|
```python
|
||||||
postlist = API.run_job('post.listpublic')
|
postlist = API.run_job('post.listpublic')
|
||||||
print(postlist)
|
print(postlist)
|
||||||
'''
|
'''
|
||||||
{
|
{
|
||||||
"Items": [
|
"Items": [
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
'''
|
'''
|
||||||
```
|
```
|
||||||
**_NOTE:_** There are aren't the complete set yet created here.
|
**_NOTE:_** There are aren't the complete set yet created here.
|
||||||
|
|
||||||
## Custom Request
|
## Custom Request
|
||||||
There should hopefully be a `job` or a `wrapper` that exists for what you need but if not, then this is how you make a request using the core mechanism.
|
There should hopefully be a `job` or a `wrapper` that exists for what you need but if not, then this is how you make a request using the core mechanism.
|
||||||
|
|
||||||
Use the `make_request` function to make a request from the content API to get posts in the music branch.
|
Use the `make_request` function to make a request from the content API to get posts in the music branch.
|
||||||
```python
|
```python
|
||||||
postlist = API.make_request("GET", "content", f"post/ref-subwiki/music")
|
postlist = API.make_request("GET", "content", f"post/ref-subwiki/music")
|
||||||
print(postlist)
|
print(postlist)
|
||||||
'''
|
'''
|
||||||
{
|
{
|
||||||
"Items": [
|
"Items": [
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
'''
|
'''
|
||||||
```
|
```
|
||||||
|
|
||||||
# Jobs
|
# Jobs
|
||||||
## block
|
## block
|
||||||
## branch
|
## branch
|
||||||
### `get`
|
### `get`
|
||||||
### `listbyname`
|
### `listbyname`
|
||||||
## change
|
## change
|
||||||
## comment
|
## comment
|
||||||
### `create`
|
### `create`
|
||||||
### `listbypostid`
|
### `listbypostid`
|
||||||
## feed
|
## feed
|
||||||
## mute
|
## mute
|
||||||
## notifcation
|
## notifcation
|
||||||
### `listnotifications`
|
### `listnotifications`
|
||||||
```python
|
```python
|
||||||
API.run_job('notification.listnotifications')
|
API.run_job('notification.listnotifications')
|
||||||
```
|
```
|
||||||
### `markallasread`
|
### `markallasread`
|
||||||
```python
|
```python
|
||||||
API.run_job('notification.markallasread')
|
API.run_job('notification.markallasread')
|
||||||
```
|
```
|
||||||
## post
|
## post
|
||||||
### create
|
### create
|
||||||
```python
|
```python
|
||||||
API.run_job('post.create', {
|
API.run_job('post.create', {
|
||||||
"postText": "This is a test post created via the API wrapper.",
|
"postText": "This is a test post created via the API wrapper.",
|
||||||
"parent": {
|
"parent": {
|
||||||
"pk": "maintrunk#maintrunk",
|
"pk": "maintrunk#maintrunk",
|
||||||
"sk": "maintrunk#maintrunk"
|
"sk": "maintrunk#maintrunk"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
### get
|
### get
|
||||||
### listall
|
### listall
|
||||||
### listbybranch
|
### listbybranch
|
||||||
### listbyuserprofile
|
### listbyuserprofile
|
||||||
### listpublic
|
### listpublic
|
||||||
### listremoved
|
### listremoved
|
||||||
### update
|
### update
|
||||||
## reaction
|
## reaction
|
||||||
## trust
|
## trust
|
||||||
## userprofile
|
## userprofile
|
||||||
## vote
|
## vote
|
||||||
|
|
||||||
|
|
||||||
# Wrappers
|
# Wrappers
|
||||||
## post
|
## post
|
||||||
### `create_post`
|
### `create_post`
|
||||||
### `update_post`
|
### `update_post`
|
||||||
## comment
|
## comment
|
||||||
### `create_comment`
|
### `create_comment`
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
Loading…
Add table
Add a link
Reference in a new issue