Initial release — APIClient - Agent v2.0.0
AI-first API testing desktop client built with Python + PyQt6. Features: - Multi-tab HTTP request editor with params/headers/body/auth/tests - KeyValueTable with per-row enable/disable checkboxes and 36px rows - Format JSON button, syntax highlighting, pre-request & test scripts - Collections, environments, history, import/export (Postman v2.1, cURL) - OpenAPI 3.x / Swagger 2.0 local parser (no AI tokens) - EKIKA Odoo API Framework generator — JSON-API, REST JSON, GraphQL, Custom REST JSON with all auth types (instant, no AI tokens) - Persistent AI chat sidebar (Claude-powered co-pilot) with streaming, context-aware suggestions, and one-click Apply to request editor - AI collection generator from any docs URL or pasted spec - WebSocket client, Mock server, Collection runner, Code generator - Dark/light theme engine (global QSS, object-name selectors) - SSL error detection with actionable hints - MIT License Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
391
README.md
391
README.md
@@ -1,2 +1,391 @@
|
||||
# APIClient-Agent
|
||||
# APIClient - Agent
|
||||
|
||||
> **AI-first API testing desktop client** — built with Python + PyQt6.
|
||||
> Specialised for the [EKIKA Odoo API Framework](https://apps.odoo.com/apps/modules/19.0/api_framework), but works with any REST, GraphQL, or WebSocket API.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Core API Testing
|
||||
- **Multi-tab request editor** — work on multiple requests simultaneously, drag to reorder
|
||||
- **All HTTP methods** — GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
|
||||
- **Smart params & headers table** — per-row enable/disable checkboxes, 36 px comfortable rows, auto-expanding blank row
|
||||
- **Body editor** — raw JSON/XML/text with syntax highlighting, **Format JSON** button, `application/vnd.api+json` support
|
||||
- **Auth panel** — Bearer Token, Basic Auth, API Key (header or query)
|
||||
- **Pre-request scripts** — Python executed before each request; access `pm.environment.get/set`
|
||||
- **Test scripts** — assertions auto-run after every response; `pm.test(...)` / `expect(...)` DSL
|
||||
- **Response viewer** — syntax-highlighted body, headers table, test results, search, copy, save
|
||||
- **WebSocket client** — connect, send, receive, log messages
|
||||
- **Mock server** — local HTTP mock with configurable routes
|
||||
|
||||
### Collections & Environments
|
||||
- **Collections sidebar** — import/export Postman Collection v2.1 JSON, cURL
|
||||
- **Environment variables** — `{{base_url}}`, `{{api_key}}`, etc. resolved at send time; per-environment values
|
||||
- **Collection runner** — run all requests in a collection, view pass/fail results
|
||||
- **History** — every sent request automatically saved
|
||||
|
||||
### AI Co-pilot (Claude-powered)
|
||||
- **Persistent AI chat sidebar** — toggle with the `✦ AI` button or `Ctrl+Shift+A`
|
||||
- **Full context awareness** — AI sees your current request (method, URL, headers, body, params, test scripts) and the last response (status, body, errors); secrets are automatically redacted
|
||||
- **Streaming responses** — tokens stream in real time
|
||||
- **One-click Apply** — AI suggestions come with **Apply Body**, **Apply Params**, **Apply Headers**, **Apply Test Script** buttons that set the values directly in the request editor
|
||||
- **Multi-turn conversation** — full history maintained per session; Clear to reset
|
||||
- **Quick actions** — Analyze, Fix Error, Gen Body, Write Tests, Auth Help, Explain Response
|
||||
- **EKIKA Odoo collection generator** — generate complete collections for JSON-API, REST JSON, GraphQL, and Custom REST JSON without spending AI tokens; supports all auth types
|
||||
|
||||
### EKIKA Odoo API Framework specialisation
|
||||
- Generates full CRUD + Execute / Export / Report / Fields / Access-Rights endpoints per model
|
||||
- Auth types: API Key (`x-api-key`), Basic Auth, User Credentials, OAuth2, JWT, Public
|
||||
- Correct JSON-API body format out of the box: `{"data": {"type": "sale.order", "attributes": {...}}}`
|
||||
- Automatic environment creation with `base_url`, `api_key`, tokens
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Requirements
|
||||
- Python 3.11+
|
||||
- Linux, macOS, or Windows
|
||||
|
||||
```bash
|
||||
git clone https://git.ekika.co/EKIKA.co/APIClient-Agent.git
|
||||
cd APIClient-Agent
|
||||
|
||||
python -m venv venv
|
||||
source venv/bin/activate # Windows: venv\Scripts\activate
|
||||
|
||||
pip install -r requirements.txt
|
||||
python main.py
|
||||
```
|
||||
|
||||
### requirements.txt
|
||||
```
|
||||
PyQt6>=6.6.0
|
||||
httpx>=0.27.0
|
||||
websockets>=12.0
|
||||
anthropic>=0.25.0
|
||||
pyyaml>=6.0
|
||||
pyinstaller>=6.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1 — Send your first request
|
||||
|
||||
1. Launch the app: `python main.py`
|
||||
2. Type a URL in the bar, e.g. `https://jsonplaceholder.typicode.com/todos/1`
|
||||
3. Press **Send** (or `Ctrl+Enter`)
|
||||
4. See the JSON response with syntax highlighting in the bottom panel
|
||||
|
||||
### 2 — Use environment variables
|
||||
|
||||
1. Click **Manage** → **New Environment** → name it `My API`
|
||||
2. Add variables:
|
||||
```
|
||||
base_url = https://api.example.com
|
||||
api_key = your-secret-key
|
||||
```
|
||||
3. Select the environment in the top bar
|
||||
4. In the URL bar, type `{{base_url}}/v1/users`
|
||||
5. In Headers, add `Authorization: Bearer {{api_key}}`
|
||||
6. Variables are resolved automatically at send time
|
||||
|
||||
### 3 — Import a collection
|
||||
|
||||
**From Postman export:**
|
||||
1. `File → Import…`
|
||||
2. Paste Postman Collection v2.1 JSON or drop the file
|
||||
|
||||
**From cURL:**
|
||||
```
|
||||
File → Import… → paste:
|
||||
curl -X POST https://api.example.com/v1/orders \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"product_id": 42, "qty": 1}'
|
||||
```
|
||||
|
||||
**From OpenAPI spec:**
|
||||
1. `Tools → AI Assistant → Import from Docs`
|
||||
2. Paste the OpenAPI JSON/YAML URL — parsed instantly, no AI tokens used
|
||||
|
||||
---
|
||||
|
||||
## EKIKA Odoo API Framework — Complete Example
|
||||
|
||||
### Generate a collection in 30 seconds
|
||||
|
||||
1. Open **Tools → AI Assistant** (or click `✦ AI` → `AI Assistant` in the menu)
|
||||
2. Select the **EKIKA Odoo API** tab
|
||||
3. Fill in:
|
||||
|
||||
| Field | Example |
|
||||
|---|---|
|
||||
| Instance URL | `https://mycompany.odoo.com` |
|
||||
| API Endpoint | `/user-jsonapi-apikey` |
|
||||
| API Kind | `JSON-API` |
|
||||
| Auth Type | `API Key` |
|
||||
| API Key | `EwKCljvZoHXsaGlxxvCHt1h4SvWLpuWW` |
|
||||
| Models | `sale.order, res.partner, account.move` |
|
||||
| Operations | ✓ List, Get, Create, Update, Delete |
|
||||
|
||||
4. Click **Generate Collection** — preview appears instantly
|
||||
5. Click **Import Both** — collection + environment are saved
|
||||
|
||||
This generates the following requests for each model with zero AI tokens:
|
||||
|
||||
```
|
||||
GET {{base_url}}/user-jsonapi-apikey/sale.order
|
||||
GET {{base_url}}/user-jsonapi-apikey/sale.order/{{id}}
|
||||
POST {{base_url}}/user-jsonapi-apikey/sale.order
|
||||
PATCH {{base_url}}/user-jsonapi-apikey/sale.order/{{id}}
|
||||
DELETE {{base_url}}/user-jsonapi-apikey/sale.order/{{id}}
|
||||
```
|
||||
|
||||
### Sending a JSON-API request
|
||||
|
||||
The generated **Create sale.order** request body:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"type": "sale.order",
|
||||
"attributes": {
|
||||
"name": "New Order"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Headers sent automatically:
|
||||
```
|
||||
x-api-key: EwKCljvZoHXsaGlxxvCHt1h4SvWLpuWW
|
||||
Content-Type: application/vnd.api+json
|
||||
Accept: application/vnd.api+json
|
||||
```
|
||||
|
||||
### Filtering and pagination (List endpoint)
|
||||
|
||||
The **List sale.order** request includes query params:
|
||||
```
|
||||
page[number] = 1
|
||||
page[size] = 10
|
||||
fields[sale.order] = id,name,display_name,partner_id
|
||||
sort = -id
|
||||
```
|
||||
|
||||
To filter by customer, open the AI chat sidebar and ask:
|
||||
> *"Add a filter param to get only sale orders for partner ID 7"*
|
||||
|
||||
AI responds with an apply block you can apply in one click.
|
||||
|
||||
### GraphQL example
|
||||
|
||||
Select **API Kind: GraphQL**. The generator creates:
|
||||
|
||||
**List sale.order (GraphQL)**
|
||||
```json
|
||||
{
|
||||
"query": "query {\n sale_order(\n filter: \"\"\n pageSize: 10\n pageNumber: 1\n ) {\n id\n name\n display_name\n }\n}"
|
||||
}
|
||||
```
|
||||
|
||||
**Create sale.order (GraphQL)**
|
||||
```json
|
||||
{
|
||||
"query": "mutation {\n create_sale_order(\n attributes: {\n name: \"New Record\"\n }\n ) {\n id\n name\n }\n}"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AI Chat Co-pilot — Example Session
|
||||
|
||||
Click **✦ AI** in the top bar to open the sidebar. The AI automatically knows what request you have open and the last response.
|
||||
|
||||
### Debugging a 401 error
|
||||
|
||||
```
|
||||
You: I'm getting 401 Unauthorized on all my Odoo API requests.
|
||||
|
||||
AI: A 401 on the EKIKA JSON-API endpoint means the x-api-key header is
|
||||
missing, empty, or incorrect.
|
||||
|
||||
Checklist:
|
||||
1. Confirm your environment has api_key set (Tools → Environments)
|
||||
2. Confirm the request Headers tab includes x-api-key: {{api_key}}
|
||||
3. In Odoo, verify the API key is still active under your user's
|
||||
API Framework settings
|
||||
|
||||
Here are the correct headers to apply:
|
||||
|
||||
┌─ apply:headers ──────────────────────────────────┐
|
||||
│ x-api-key: {{api_key}} │
|
||||
│ Accept: application/vnd.api+json │
|
||||
└──────────────────────────────────────────────────┘
|
||||
[ Apply Headers to Request ]
|
||||
```
|
||||
|
||||
Click **Apply Headers to Request** — headers are set immediately and the Headers tab opens.
|
||||
|
||||
### Generating a body for a complex model
|
||||
|
||||
```
|
||||
You: Generate a body to create an invoice (account.move) for partner ID 14,
|
||||
with one line for product ID 7, quantity 3, price 150.
|
||||
|
||||
AI: Here is a JSON-API compliant body for creating an account.move:
|
||||
|
||||
┌─ apply:body ─────────────────────────────────────┐
|
||||
│ { │
|
||||
│ "data": { │
|
||||
│ "type": "account.move", │
|
||||
│ "attributes": { │
|
||||
│ "move_type": "out_invoice", │
|
||||
│ "partner_id": 14, │
|
||||
│ "invoice_line_ids": [[0, 0, { │
|
||||
│ "product_id": 7, │
|
||||
│ "quantity": 3, │
|
||||
│ "price_unit": 150.0 │
|
||||
│ }]] │
|
||||
│ } │
|
||||
│ } │
|
||||
│ } │
|
||||
└──────────────────────────────────────────────────┘
|
||||
[ Apply Body to Request ]
|
||||
```
|
||||
|
||||
### Writing test scripts
|
||||
|
||||
```
|
||||
You: Write tests to verify a successful JSON-API list response.
|
||||
|
||||
AI: ┌─ apply:test ─────────────────────────────────────┐
|
||||
│ pm.test('Status 200', lambda: │
|
||||
│ pm.response.to_have_status(200)) │
|
||||
│ pm.test('Has data array', lambda: │
|
||||
│ expect(pm.response.json()).to_have_key('data'))│
|
||||
│ pm.test('Data is list', lambda: │
|
||||
│ expect(pm.response.json()['data']).to_be_list())│
|
||||
│ pm.test('Response time < 2s', lambda: │
|
||||
│ expect(pm.response.response_time).to_be_below(2000))│
|
||||
└──────────────────────────────────────────────────┘
|
||||
[ Apply Test Script to Request ]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
| Shortcut | Action |
|
||||
|---|---|
|
||||
| `Ctrl+Enter` | Send request |
|
||||
| `Ctrl+T` | New tab |
|
||||
| `Ctrl+W` | Close tab |
|
||||
| `Ctrl+S` | Save to collection |
|
||||
| `Ctrl+F` | Search requests |
|
||||
| `Ctrl+E` | Manage environments |
|
||||
| `Ctrl+Shift+A` | Toggle AI chat sidebar |
|
||||
| `Ctrl+Shift+F` | Format JSON body |
|
||||
| `Escape` | Cancel in-flight request |
|
||||
| `Ctrl+Q` | Quit |
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
APIClient-Agent/
|
||||
├── main.py # Entry point
|
||||
├── requirements.txt
|
||||
├── LICENSE
|
||||
├── app/
|
||||
│ ├── models.py # HttpRequest, HttpResponse, Environment
|
||||
│ ├── core/
|
||||
│ │ ├── storage.py # SQLite persistence (collections, environments, history)
|
||||
│ │ ├── http_client.py # httpx-based request engine, variable resolution
|
||||
│ │ ├── ai_client.py # Claude API — collection generation from docs
|
||||
│ │ ├── ai_chat.py # Claude API — multi-turn conversational co-pilot
|
||||
│ │ ├── openapi_parser.py # OpenAPI 3.x / Swagger 2.0 local parser
|
||||
│ │ ├── ekika_odoo_generator.py# EKIKA Odoo framework collection generator
|
||||
│ │ ├── test_runner.py # pm.test / expect assertion engine
|
||||
│ │ ├── mock_server.py # Local HTTP mock server
|
||||
│ │ ├── code_gen.py # Code generation (curl, Python, JS, etc.)
|
||||
│ │ ├── exporter.py # Postman Collection v2.1 export
|
||||
│ │ └── importer.py # Postman Collection / cURL import
|
||||
│ └── ui/
|
||||
│ ├── main_window.py # Main window, splitter layout, env bar
|
||||
│ ├── theme.py # Central QSS stylesheet engine (dark/light)
|
||||
│ ├── request_panel.py # URL bar, params/headers/body/auth/tests editor
|
||||
│ ├── response_panel.py # Response viewer with status badge
|
||||
│ ├── tabs_manager.py # Multi-tab request manager
|
||||
│ ├── sidebar.py # Collections tree sidebar
|
||||
│ ├── ai_panel.py # AI Assistant dialog (collection generator)
|
||||
│ ├── ai_chat_panel.py # AI chat sidebar (co-pilot)
|
||||
│ ├── environment_dialog.py # Environment manager
|
||||
│ ├── collection_runner.py # Collection runner
|
||||
│ ├── websocket_panel.py # WebSocket client
|
||||
│ ├── mock_server_panel.py # Mock server UI
|
||||
│ ├── import_dialog.py # Import dialog
|
||||
│ ├── code_gen_dialog.py # Code generation dialog
|
||||
│ ├── search_dialog.py # Request search
|
||||
│ └── highlighter.py # JSON syntax highlighter
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Settings are stored in an SQLite database at `~/.apiclient_agent/data.db` (created automatically).
|
||||
|
||||
### Anthropic API Key (for AI features)
|
||||
|
||||
1. Get a key at [console.anthropic.com](https://console.anthropic.com)
|
||||
2. In the app: `Tools → AI Assistant → Settings tab`
|
||||
3. Paste the key and click **Save API Key**
|
||||
|
||||
The key is stored locally in the SQLite database only — never transmitted except to the Anthropic API.
|
||||
|
||||
---
|
||||
|
||||
## SSL / TLS Notes
|
||||
|
||||
Some servers (especially demo/development instances) use self-signed certificates or wildcard certificates that don't match the exact hostname. If you see:
|
||||
|
||||
```
|
||||
SSL certificate error — could not connect to https://...
|
||||
Tip: disable SSL verification in the request Settings tab.
|
||||
```
|
||||
|
||||
Open the **Settings** tab in the request editor and uncheck **Verify SSL certificate**.
|
||||
|
||||
---
|
||||
|
||||
## Building a Standalone Executable
|
||||
|
||||
```bash
|
||||
pyinstaller --onefile --windowed \
|
||||
--name "APIClient-Agent" \
|
||||
--add-data "app:app" \
|
||||
main.py
|
||||
```
|
||||
|
||||
The executable is produced in `dist/APIClient-Agent`.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch: `git checkout -b feature/my-feature`
|
||||
3. Commit your changes: `git commit -m "Add my feature"`
|
||||
4. Push and open a pull request
|
||||
|
||||
Please keep UI styling in `theme.py` using `setObjectName()` selectors — never inline `setStyleSheet()` for static colors.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](LICENSE) — Copyright (c) 2026 EKIKA.co
|
||||
|
||||
Reference in New Issue
Block a user