chore: add comprehensive API wrapper documentation
- Add docs/ directory with 6 comprehensive documentation files: * INDEX.md - Main navigation and documentation index * GETTING_STARTED.md - Setup and configuration guide * API_REFERENCE.md - Complete API documentation * WRAPPERS.md - High-level wrappers guide * CUSTOM_REQUESTS.md - Advanced usage patterns * TROUBLESHOOTING.md - Problem-solving guide - Update README.md with enhanced project information - Update development.md with expanded documentation context Extends previous session's documentation work with complete developer and user-facing documentation. Closes previous documentation issue.
This commit is contained in:
parent
14346ed02e
commit
fd1a1566e9
8 changed files with 4909 additions and 61 deletions
763
docs/TROUBLESHOOTING.md
Normal file
763
docs/TROUBLESHOOTING.md
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
# Troubleshooting Guide
|
||||
|
||||
Common issues and solutions when using the TrustCafé API wrapper.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Authentication Issues](#authentication-issues)
|
||||
- [Connection Issues](#connection-issues)
|
||||
- [Token Management Issues](#token-management-issues)
|
||||
- [API Call Issues](#api-call-issues)
|
||||
- [Environment Issues](#environment-issues)
|
||||
- [Data Handling Issues](#data-handling-issues)
|
||||
- [Performance Issues](#performance-issues)
|
||||
- [Debugging Strategies](#debugging-strategies)
|
||||
|
||||
## Authentication Issues
|
||||
|
||||
### Issue: "Invalid client credentials"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ValueError: Client credentials invalid
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Incorrect client_id or client_secret
|
||||
- Using alpha credentials on production environment (or vice versa)
|
||||
- Credentials haven't been saved yet from the TrustCafé admin panel
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Verify credentials from the admin panel
|
||||
2. Ensure environment matches credentials:
|
||||
```python
|
||||
# Check your credentials are for the right environment
|
||||
print(f"Environment: {env}") # Should match where credentials were created
|
||||
```
|
||||
|
||||
3. Generate new credentials if needed:
|
||||
- Visit: https://www.trustcafe.io/en/myaccount/apiaccess
|
||||
- Click "Create new client credentials key pair"
|
||||
- Save the new credentials
|
||||
|
||||
4. Verify credentials aren't expired (trustcafe-side expiration)
|
||||
|
||||
---
|
||||
|
||||
### Issue: "Token expired"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
Exception: Token has expired
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Access token duration has expired (~3 months from creation)
|
||||
- Time mismatch between systems
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Automatically refresh token:
|
||||
```python
|
||||
# Check token validity and refresh if needed
|
||||
if not API.is_token_valid():
|
||||
API.handle_token()
|
||||
```
|
||||
|
||||
2. Pre-load tokens before long operations:
|
||||
```python
|
||||
# Ensure token is fresh before making many requests
|
||||
API.handle_token()
|
||||
|
||||
# Now all API calls will succeed
|
||||
```
|
||||
|
||||
3. Provide longer expiration time for testing:
|
||||
```python
|
||||
# Manual token with long expiration
|
||||
API.set_token({
|
||||
"access_token": "your-token",
|
||||
"access_token_timeout": 9999999999 # Far future date
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "Permission denied" when making requests
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ForbiddenError: Insufficient permissions for this API endpoint
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Client credentials lack required scopes
|
||||
- Not authenticated (no access token)
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Verify scopes on the admin panel
|
||||
2. Ensure authentication is enabled in all requests:
|
||||
```python
|
||||
# Make sure to authenticate
|
||||
response = API.make_request(
|
||||
"GET",
|
||||
"content",
|
||||
"some/path",
|
||||
authenticate=True # Ensure this is True
|
||||
)
|
||||
|
||||
# For guest requests (if allowed)
|
||||
response = API.make_request(
|
||||
"GET",
|
||||
"content",
|
||||
"some/path",
|
||||
authenticate=False
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Connection Issues
|
||||
|
||||
### Issue: "No internet connection" or "Connection refused"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ConnectionError: An error occurred while making the request
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Network connectivity issues
|
||||
- Firewall blocking requests
|
||||
- API service unavailable
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check network connectivity:
|
||||
```bash
|
||||
# Test connectivity to alpha/production endpoints
|
||||
ping alpha.wts2.net
|
||||
ping trustcafe.io
|
||||
```
|
||||
|
||||
2. Verify firewall rules allow HTTPS requests
|
||||
|
||||
3. Try alternative network (mobile hotspot vs. Wi-Fi)
|
||||
|
||||
4. Check if TrustCafé services are up:
|
||||
- Production: https://trustcafe.io
|
||||
- Alpha: https://alpha.wts2.net
|
||||
|
||||
5. Add retry logic:
|
||||
```python
|
||||
import time
|
||||
|
||||
def retry_request(request_func, max_retries=3):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return request_func()
|
||||
except ConnectionError as e:
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "DNS resolution failed"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
requests.exceptions.ConnectionError: DNS resolution failed
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- DNS server issues
|
||||
- VPN interfering with DNS
|
||||
- Incorrect hostname
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check DNS:
|
||||
```bash
|
||||
nslookup alpha.wts2.net
|
||||
nslookup trustcafe.io
|
||||
```
|
||||
|
||||
2. Try changing DNS server:
|
||||
```bash
|
||||
# Use Google DNS (8.8.8.8, 8.8.4.4)
|
||||
# Or Cloudflare (1.1.1.1, 1.0.0.1)
|
||||
```
|
||||
|
||||
3. Disable VPN temporarily
|
||||
4. Check configuration for correct hostnames (alpha.wts2.net vs trustcafe.io)
|
||||
|
||||
---
|
||||
|
||||
## Token Management Issues
|
||||
|
||||
### Issue: "Token file not found"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
FileNotFoundError: Token data file 'token_data_alpha.json' not found
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- First-time run
|
||||
- Token directory not created
|
||||
- Wrong path specified
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. API `<environment>_handle_token` automatically creates file on first use
|
||||
|
||||
2. Ensure working directory is writable
|
||||
|
||||
3. Specify custom token file path:
|
||||
```python
|
||||
API.handle_token(token_data_path="my/custom/path/token_data.json")
|
||||
```
|
||||
|
||||
4. Manually create token file:
|
||||
```python
|
||||
token_data = API.sign_in()
|
||||
with open("token_data_alpha.json", "w") as f:
|
||||
json.dump(token_data, f)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "Permission denied: cannot write token file"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
PermissionError: [Errno 13] Permission denied: 'token_data_alpha.json'
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Working directory not writable
|
||||
- File locked by another process
|
||||
- Insufficient permissions
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Ensure writable directory:
|
||||
```python
|
||||
import os
|
||||
|
||||
# Use a writable directory
|
||||
writable_dir = os.path.expanduser("~") # Home directory
|
||||
API.handle_token(token_data_path=f"{writable_dir}/tokens/token_data.json")
|
||||
```
|
||||
|
||||
2. Check file permissions:
|
||||
```bash
|
||||
ls -la token_data_alpha.json
|
||||
chmod 644 token_data_alpha.json
|
||||
```
|
||||
|
||||
3. Try with a custom directory:
|
||||
```python
|
||||
import tempfile
|
||||
|
||||
# Use temp directory
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
API.handle_token(token_data_path=f"{tmpdir}/token_data.json")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "Token file corrupted"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- File corruption during write
|
||||
- File truncated by other process
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Delete corrupted token file:
|
||||
```bash
|
||||
rm token_data_alpha.json
|
||||
```
|
||||
|
||||
2. Let wrapper recreate it
|
||||
|
||||
3. Check for concurrent token writes:
|
||||
```python
|
||||
from threading import Lock
|
||||
|
||||
token_lock = Lock()
|
||||
|
||||
def safe_handle_token():
|
||||
with token_lock:
|
||||
API.handle_token()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Call Issues
|
||||
|
||||
### Issue: "400 Bad Request" or "Invalid parameter"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ValueError: Invalid parameter or data format
|
||||
400 Bad Request
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Missing required parameters
|
||||
- Incorrect parameter format
|
||||
- Parameter validation failure
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check parameter requirements in API Reference:
|
||||
- See [API Reference](api_reference.md) for each job
|
||||
|
||||
2. Verify parameter types:
|
||||
```python
|
||||
# Use correct types
|
||||
API.run_job('post.create', {
|
||||
"postText": "text string", # Should be string
|
||||
"blurLabel": None, # None is okay
|
||||
# Wrong: "blurLabel": "" (empty string)
|
||||
})
|
||||
```
|
||||
|
||||
3. Verify required parameters:
|
||||
```python
|
||||
# Example for post.create
|
||||
required_fields = ['postText', 'parent']
|
||||
|
||||
if 'parent' not in data:
|
||||
raise ValueError("Required field 'parent' is missing")
|
||||
```
|
||||
|
||||
4. Use debug mode to see request:
|
||||
```python
|
||||
API = APIClient(debug=True)
|
||||
|
||||
# Now you'll see the exact data being sent
|
||||
API.run_job('post.create', data)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "404 Not Found"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
FileNotFoundError: Endpoint not found
|
||||
404 Not Found
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Wrong endpoint or path
|
||||
- Resource doesn't exist
|
||||
- Branch/post not found
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Verify the path is correct
|
||||
2. Check if resource exists:
|
||||
```python
|
||||
# Verify branch exists
|
||||
branch = API.run_job('branch.get', "branch-name")
|
||||
|
||||
if not branch:
|
||||
print("Branch does not exist")
|
||||
|
||||
# Verify post exists
|
||||
post = API.run_job('post.get', "post-id")
|
||||
|
||||
if not post:
|
||||
print("Post does not exist")
|
||||
```
|
||||
|
||||
3. Check for spelling mistakes in paths
|
||||
|
||||
4. Use debug mode to see exact path being sent:
|
||||
```python
|
||||
API = APIClient(debug=True)
|
||||
API.run_job('post.create', data) # See exact request path
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "500 Internal Server Error"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ConnectionError: An error occurred
|
||||
500 Internal Server Error
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- TrustCafé server error
|
||||
- Database issues on server side
|
||||
- Unhandled edge case
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Wait a moment and retry
|
||||
2. Check TrustCafé status
|
||||
3. Try at a different time
|
||||
4. Consider this transient error:
|
||||
```python
|
||||
import time
|
||||
|
||||
def retry_server_error(func, max_retries=3):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return func()
|
||||
except ConnectionError as e:
|
||||
if str(e).find("500") != -1:
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(2 ** attempt) # Exponential backoff
|
||||
else:
|
||||
raise
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "Rate limit exceeded"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
429 Too Many Requests
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Too many API calls too quickly
|
||||
- Gratuitous API usage
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Implement rate limiting (see main README for example)
|
||||
|
||||
2. Space out your API calls:
|
||||
```python
|
||||
import time
|
||||
|
||||
def spaced_request(request_func, delay=1):
|
||||
result = request_func()
|
||||
if hasattr(request_func, 'call_count'):
|
||||
request_func.call_count += 1
|
||||
if request_func.call_count > 30:
|
||||
time.sleep(2)
|
||||
return result
|
||||
```
|
||||
|
||||
3. Use pagination for large result sets
|
||||
|
||||
4. Consider caching results when possible
|
||||
|
||||
---
|
||||
|
||||
## Environment Issues
|
||||
|
||||
### Issue: "Environment 'invalid' is not valid"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ValueError: Environment 'staging' is not valid. Must be one of: ['alpha', 'production']
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Typo in environment name
|
||||
- Passing only environment once
|
||||
- Environment changed incorrectly
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Use correct environment names:
|
||||
- "alpha" (development/staging)
|
||||
- "production" (live)
|
||||
|
||||
2. Avoid modifying environment mid-session after API init
|
||||
|
||||
3. Reinitialize if you need to switch:
|
||||
```python
|
||||
# Create new API client for new environment
|
||||
API_prod = APIClient(
|
||||
client_id="prod-id",
|
||||
client_secret="prod-secret",
|
||||
env="production"
|
||||
)
|
||||
|
||||
# Old API still has old environment
|
||||
print(API.environment) # "alpha"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: "Endpoint 'invalid' is not defined"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ValueError: Endpoint 'noservices' is not defined in the API client.
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Typo in endpoint name
|
||||
- Custom endpoint not configured
|
||||
- Server-side endpoint changed
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check available endpoints in APIClient code
|
||||
2. Use correct endpoints: "content", "auth", "audrey", etc.
|
||||
3. Review documentation for correct API structure
|
||||
|
||||
---
|
||||
|
||||
## Data Handling Issues
|
||||
|
||||
### Issue: "JSON decode error" or "Response is not valid JSON"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
ValueError: Response is not valid JSON: Expecting value: line 1 column 1 (char 0)
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Server returning non-JSON response
|
||||
- Network error causing incomplete response
|
||||
- Empty response
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Add error handling:
|
||||
```python
|
||||
try:
|
||||
response = API.make_request("GET", "content", "path")
|
||||
response_json = response.json()
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Failed to parse JSON: {e}")
|
||||
print(f"Response was: {response}")
|
||||
```
|
||||
|
||||
2. Check if server is responding correctly
|
||||
|
||||
3. Verify network connectivity
|
||||
|
||||
4. Check for errors in response:
|
||||
```python
|
||||
if 'error' in response:
|
||||
raise Exception(f"API Error: {response['error']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue: Empty response or missing data
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
expected to find Items in response, but didn't
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Query returns no results
|
||||
- Pagination not handled
|
||||
- Response structure misunderstanding
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check for empty results:
|
||||
```python
|
||||
response = API.make_request("GET", "content", "some/path")
|
||||
|
||||
if 'Items' not in response or not response.get('Items'):
|
||||
print("No results found")
|
||||
```
|
||||
|
||||
2. Check pagination status:
|
||||
```python
|
||||
if 'LastEvaluatedKey' in response:
|
||||
print("More results available, need pagination")
|
||||
```
|
||||
|
||||
3. Verify response structure understanding
|
||||
|
||||
---
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Issue: "Timeout" errors
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
requests.exceptions.Timeout: Request timed out
|
||||
```
|
||||
|
||||
**Causes:**
|
||||
- Network slowness
|
||||
- Large result sets
|
||||
- Slow server response
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Increase timeout:
|
||||
```python
|
||||
# Unfortunately, current implementation doesn't expose timeout
|
||||
# This would need updating in apiclient.py
|
||||
|
||||
# If you control code, you can modify the make_request method
|
||||
# to accept a timeout parameter
|
||||
```
|
||||
|
||||
2. Reduce request complexity
|
||||
|
||||
3. Implement pagination for large datasets
|
||||
|
||||
4. Use async if available
|
||||
|
||||
---
|
||||
|
||||
### Issue: Slow token refresh
|
||||
|
||||
**Symptoms:**
|
||||
- Initial request slow
|
||||
- Token refresh takes too long
|
||||
|
||||
**Causes:**
|
||||
- Network latency to auth endpoint
|
||||
- Server-side delays
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Pre-load token:
|
||||
```python
|
||||
# Get token before doing anything time-sensitive
|
||||
API.handle_token()
|
||||
|
||||
# All subsequent calls will use cached token
|
||||
```
|
||||
|
||||
2. Use manual token for frequent operations:
|
||||
```python
|
||||
API.set_token({
|
||||
"access_token": token,
|
||||
"access_token_timeout": 9999999999
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging Strategies
|
||||
|
||||
### Enable Debug Mode
|
||||
|
||||
```python
|
||||
API = APIClient(
|
||||
client_id="your-id",
|
||||
client_secret="your-secret",
|
||||
env="alpha",
|
||||
debug=True # Enables verbose logging
|
||||
)
|
||||
```
|
||||
|
||||
This will print:
|
||||
- Request method
|
||||
- Full URL
|
||||
- Headers
|
||||
- Request payload
|
||||
|
||||
### Add Logging
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
result = API.run_job('post.create', data)
|
||||
logger.debug(f"Success: {result}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed: {e}", exc_info=True)
|
||||
```
|
||||
|
||||
### Verify Request Flow
|
||||
|
||||
```python
|
||||
def trace_request(func, *args, **kwargs):
|
||||
"""Trace each request"""
|
||||
import inspect
|
||||
|
||||
# Get function name
|
||||
func_name = inspect.getmember(BuiltinFunctionType, func).__name__
|
||||
|
||||
print(f"Calling: {func_name}")
|
||||
print(f"Args: {args}")
|
||||
print(f"Kwargs: {kwargs}")
|
||||
|
||||
result = func(*args, **kwargs)
|
||||
|
||||
print(f"Result: {result}")
|
||||
return result
|
||||
```
|
||||
|
||||
### Network Inspection
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
# Direct inspection of requests
|
||||
import logging
|
||||
requests_log = logging.getLogger("urllib3")
|
||||
requests_log.setLevel(logging.DEBUG)
|
||||
|
||||
requests_log.propagate = True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you've tried all of the above and still have issues:
|
||||
|
||||
1. **Check the Code**: Review the latest version on GitLab
|
||||
- [GitLab Repository](https://gitlab.com/trustcafe/trustcafe-api-wrapper)
|
||||
|
||||
2. **Check TrustCafé Status**: Verify services are up
|
||||
- [Production](https://trustcafe.io)
|
||||
- [Alpha](https://alpha.wts2.net)
|
||||
|
||||
3. **Review Contributions**: Check for known issues
|
||||
- Open an issue on GitLab
|
||||
- Check if a fix is already in progress
|
||||
|
||||
4. **Contact Support**: For resolved but unreleased issues
|
||||
- WikiTribune team
|
||||
- Build Product Slack/Discord
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
Common error codes:
|
||||
|
||||
- **400 Bad Request**: Invalid parameters (check API Reference)
|
||||
- **401 Unauthorized**: Invalid/missing token (call `handle_token()`)
|
||||
- **403 Forbidden**: Insufficient permissions (check scopes)
|
||||
- **404 Not Found**: Wrong path or resource doesn't exist
|
||||
- **429 Too Many Requests**: Rate limit exceeded (apply rate limiting)
|
||||
- **500 Internal Server Error**: Service error (wait and retry)
|
||||
- **Timeout**: Network issues (check connectivity)
|
||||
|
||||
---
|
||||
|
||||
**Remember**: Most issues are easily solved with proper error handling, verification of credentials, and rate limiting.
|
||||
Loading…
Add table
Add a link
Reference in a new issue