394 lines
14 KiB
Markdown
394 lines
14 KiB
Markdown
# 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
|