Add Python client, profile endpoint, and functional test
- remarkbox_client.py: stdlib-only Python client with cookie persistence, 3-tier config (args/env/file), CLI mode - GET/PATCH /api/v1/user/profile: read and update display name - GET /api/v1/clients/python: serve client for curl/wget download - functional_test.py: idempotent live test that maintains a journey thread documenting each run - Remove email2 spam honeypot from API (not useful for agents) - Bump content limit to 500k chars (~128k tokens)
This commit is contained in:
parent
9d59a3ca8a
commit
5a10e155bd
8 changed files with 1287 additions and 4 deletions
|
|
@ -189,7 +189,7 @@ Request body:
|
|||
|
||||
- `namespace` (required)
|
||||
- `title` (required)
|
||||
- `data` (required, max 50000 chars)
|
||||
- `data` (required, max 500000 chars)
|
||||
- `anonymous_name` (optional, used when namespace allows anonymous)
|
||||
- `email` (optional, creates an unverified user)
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ Request body:
|
|||
}
|
||||
```
|
||||
|
||||
- `data` (required, max 50000 chars)
|
||||
- `data` (required, max 500000 chars)
|
||||
- `anonymous_name` (optional)
|
||||
- `email` (optional)
|
||||
|
||||
|
|
@ -361,7 +361,7 @@ All errors return a JSON body with an `error` key:
|
|||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| 400 | Bad request (missing params, content too long) |
|
||||
| 401 | Authentication required or spam detected |
|
||||
| 401 | Authentication required |
|
||||
| 403 | Forbidden (locked thread, disabled node, namespace opt-out) |
|
||||
| 404 | Not found (or API globally disabled) |
|
||||
| 429 | Rate limit exceeded |
|
||||
|
|
|
|||
153
docs/testing.md
Normal file
153
docs/testing.md
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
# Functional Testing the Remarkbox API
|
||||
|
||||
Walkthrough for testing every endpoint with `curl`. Replace
|
||||
`REMARKBOX` with your deploy URL (e.g. `https://my.remarkbox.com`).
|
||||
|
||||
## Read Endpoints
|
||||
|
||||
### List Threads
|
||||
|
||||
```bash
|
||||
curl -s "$REMARKBOX/api/v1/threads?namespace=meta.remarkbox.com" | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Get Thread
|
||||
|
||||
```bash
|
||||
# grab the first thread id from the list
|
||||
THREAD_ID=$(curl -s "$REMARKBOX/api/v1/threads?namespace=meta.remarkbox.com" \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['threads'][0]['id'])")
|
||||
|
||||
curl -s "$REMARKBOX/api/v1/threads/$THREAD_ID" | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Get Node
|
||||
|
||||
```bash
|
||||
curl -s "$REMARKBOX/api/v1/nodes/$THREAD_ID" | python3 -m json.tool
|
||||
```
|
||||
|
||||
## Anonymous Posting
|
||||
|
||||
Requires a namespace with **Allow Anonymous Comments** enabled.
|
||||
|
||||
### Create Thread
|
||||
|
||||
```bash
|
||||
curl -s -X POST "$REMARKBOX/api/v1/threads" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"namespace": "meta.remarkbox.com",
|
||||
"title": "Test thread from curl",
|
||||
"data": "Hello from the API.",
|
||||
"anonymous_name": "CurlBot"
|
||||
}' | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Reply to Thread
|
||||
|
||||
```bash
|
||||
curl -s -X POST "$REMARKBOX/api/v1/threads/$THREAD_ID/replies" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"data": "Reply from curl.",
|
||||
"anonymous_name": "CurlBot"
|
||||
}' | python3 -m json.tool
|
||||
```
|
||||
|
||||
## Authentication (Email OTP)
|
||||
|
||||
### Request OTP
|
||||
|
||||
```bash
|
||||
curl -s -X POST "$REMARKBOX/api/v1/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "you@example.com"}' | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Verify OTP
|
||||
|
||||
Check your inbox for the 6-digit code, then:
|
||||
|
||||
```bash
|
||||
curl -s -X POST "$REMARKBOX/api/v1/auth/verify" \
|
||||
-H "Content-Type: application/json" \
|
||||
-c cookies.txt \
|
||||
-d '{"email": "you@example.com", "otp": "123456"}' | python3 -m json.tool
|
||||
```
|
||||
|
||||
The `-c cookies.txt` saves the session cookie for subsequent requests.
|
||||
|
||||
### Create Authenticated Thread
|
||||
|
||||
```bash
|
||||
curl -s -X POST "$REMARKBOX/api/v1/threads" \
|
||||
-H "Content-Type: application/json" \
|
||||
-b cookies.txt \
|
||||
-d '{
|
||||
"namespace": "meta.remarkbox.com",
|
||||
"title": "Authenticated thread",
|
||||
"data": "Posted with a verified session."
|
||||
}' | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Edit a Node
|
||||
|
||||
```bash
|
||||
curl -s -X PATCH "$REMARKBOX/api/v1/nodes/$NODE_ID" \
|
||||
-H "Content-Type: application/json" \
|
||||
-b cookies.txt \
|
||||
-d '{"data": "Updated content."}' | python3 -m json.tool
|
||||
```
|
||||
|
||||
## Error Cases
|
||||
|
||||
### Missing namespace
|
||||
|
||||
```bash
|
||||
curl -s "$REMARKBOX/api/v1/threads" | python3 -m json.tool
|
||||
# {"error": "namespace parameter is required"}
|
||||
```
|
||||
|
||||
### Namespace with API access disabled
|
||||
|
||||
```bash
|
||||
curl -s "$REMARKBOX/api/v1/threads?namespace=opted-out.example.com"
|
||||
# {"error": "API access is disabled for this namespace"}
|
||||
```
|
||||
|
||||
### Edit without auth
|
||||
|
||||
```bash
|
||||
curl -s -X PATCH "$REMARKBOX/api/v1/nodes/$NODE_ID" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"data": "nope"}'
|
||||
# {"error": "Authentication required"}
|
||||
```
|
||||
|
||||
## Python Client
|
||||
|
||||
Download the Python client directly from the API:
|
||||
|
||||
```bash
|
||||
curl -s "$REMARKBOX/api/v1/clients/python" -o remarkbox_client.py
|
||||
```
|
||||
|
||||
Or with wget:
|
||||
|
||||
```bash
|
||||
wget -q "$REMARKBOX/api/v1/clients/python" -O remarkbox_client.py
|
||||
```
|
||||
|
||||
Then use it:
|
||||
|
||||
```python
|
||||
from remarkbox_client import RemarkboxClient
|
||||
|
||||
client = RemarkboxClient("https://my.remarkbox.com")
|
||||
threads = client.list_threads("meta.remarkbox.com")
|
||||
for t in threads["threads"]:
|
||||
print(t["title"])
|
||||
```
|
||||
|
||||
See `remarkbox_client.py` header comments for full usage.
|
||||
Loading…
Add table
Add a link
Reference in a new issue