Files
APIClient-Agent/app/core/importer.py
Anand Shukla 01662f7e0e 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>
2026-03-28 17:38:57 +05:30

104 lines
3.5 KiB
Python

"""Import from Postman Collection v2.1 JSON or curl command."""
import json
import re
import shlex
from app.models import HttpRequest
def from_postman_collection(json_text: str) -> tuple[str, list[HttpRequest]]:
"""Returns (collection_name, list of HttpRequest)."""
data = json.loads(json_text)
name = data.get("info", {}).get("name", "Imported Collection")
requests = []
def parse_item(item):
if "request" in item:
r = item["request"]
method = r.get("method", "GET")
url_obj = r.get("url", {})
if isinstance(url_obj, str):
url = url_obj
params = {}
else:
raw = url_obj.get("raw", "")
url = raw.split("?")[0] if "?" in raw else raw
params = {}
for qp in url_obj.get("query", []):
if not qp.get("disabled"):
params[qp.get("key", "")] = qp.get("value", "")
headers = {}
for h in r.get("header", []):
if not h.get("disabled"):
headers[h.get("key", "")] = h.get("value", "")
body_obj = r.get("body", {})
body = ""
body_type = "raw"
if body_obj:
mode = body_obj.get("mode", "raw")
if mode == "raw":
body = body_obj.get("raw", "")
body_type = "raw"
elif mode == "urlencoded":
pairs = body_obj.get("urlencoded", [])
body = "&".join(f"{p['key']}={p.get('value','')}" for p in pairs if not p.get("disabled"))
body_type = "urlencoded"
requests.append(HttpRequest(
method=method, url=url, headers=headers,
params=params, body=body, body_type=body_type,
name=item.get("name", "")
))
elif "item" in item:
for sub in item["item"]:
parse_item(sub)
for item in data.get("item", []):
parse_item(item)
return name, requests
def from_curl(curl_cmd: str) -> HttpRequest:
"""Parse a curl command string into an HttpRequest."""
# Normalize line continuations
cmd = curl_cmd.replace("\\\n", " ").strip()
try:
tokens = shlex.split(cmd)
except ValueError:
tokens = cmd.split()
req = HttpRequest(method="GET")
i = 1 # skip 'curl'
while i < len(tokens):
token = tokens[i]
if token in ("-X", "--request") and i + 1 < len(tokens):
req.method = tokens[i + 1].upper()
i += 2
elif token in ("-H", "--header") and i + 1 < len(tokens):
header = tokens[i + 1]
if ":" in header:
k, _, v = header.partition(":")
req.headers[k.strip()] = v.strip()
i += 2
elif token in ("-d", "--data", "--data-raw", "--data-binary") and i + 1 < len(tokens):
req.body = tokens[i + 1]
if req.method == "GET":
req.method = "POST"
i += 2
elif token in ("-u", "--user") and i + 1 < len(tokens):
user_pass = tokens[i + 1]
if ":" in user_pass:
u, _, p = user_pass.partition(":")
req.auth_type = "basic"
req.auth_data = {"username": u, "password": p}
i += 2
elif not token.startswith("-") and not req.url:
req.url = token.strip("'\"")
i += 1
else:
i += 1
return req