← 返回 Skills 市场
534422530

API接口测试

作者 534422530 · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
25
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install laosi-api-tester
功能描述
API测试 - 构建/发送HTTP请求,验证响应状态码/头/体,性能基准(延迟/吞吐量),支持REST和GraphQL
使用说明 (SKILL.md)

API Tester - API接口测试

激活词: 测试API / api test / 接口测试

功能

  • 发送 GET/POST/PUT/DELETE 请求
  • 自定义请求头、Body (JSON/Form/Text)
  • 响应状态码、头、体验证
  • GraphQL 查询支持
  • 延迟测量和性能基准
  • 测试结果持久化

Python 实现

import json, time, urllib.request, urllib.error
from datetime import datetime
from typing import Dict, Any, Optional, List
from dataclasses import dataclass, field, asdict

@dataclass
class APIRequest:
    method: str = "GET"
    url: str = ""
    headers: Dict[str, str] = field(default_factory=dict)
    body: Optional[str] = None
    content_type: str = "application/json"
    timeout: int = 10
    
    def to_urllib_request(self) -> urllib.request.Request:
        """转换为urllib请求对象"""
        data = None
        if self.body and self.method in ("POST", "PUT", "PATCH"):
            data = self.body.encode("utf-8") if isinstance(self.body, str) else self.body
            if "Content-Type" not in self.headers:
                self.headers["Content-Type"] = self.content_type
        
        req = urllib.request.Request(
            self.url,
            data=data,
            headers=self.headers,
            method=self.method
        )
        return req

@dataclass
class APIResponse:
    status: int = 0
    headers: Dict[str, str] = field(default_factory=dict)
    body: str = ""
    body_json: Optional[Dict] = None
    latency_ms: float = 0.0
    error: Optional[str] = None

class APITester:
    def __init__(self):
        self.history: List[Dict] = []
        self.history_file = os.path.join(
            os.path.dirname(__file__), "api_tests.json"
        )
        os.makedirs(os.path.dirname(self.history_file), exist_ok=True)
    
    def send(self, request: APIRequest) -> APIResponse:
        """发送单个API请求"""
        resp = APIResponse()
        start = time.time()
        
        try:
            req = request.to_urllib_request()
            with urllib.request.urlopen(req, timeout=request.timeout) as conn:
                resp.status = conn.status
                resp.headers = dict(conn.headers)
                resp.body = conn.read().decode("utf-8", errors="replace")
                try:
                    resp.body_json = json.loads(resp.body)
                except json.JSONDecodeError:
                    pass
        except urllib.error.HTTPError as e:
            resp.status = e.code
            resp.headers = dict(e.headers)
            resp.body = e.read().decode("utf-8", errors="replace")
            resp.error = f"HTTP {e.code}: {e.reason}"
        except urllib.error.URLError as e:
            resp.error = f"URL Error: {e.reason}"
        except Exception as e:
            resp.error = str(e)
        
        resp.latency_ms = round((time.time() - start) * 1000, 1)
        
        # 保存历史
        entry = {
            "method": request.method,
            "url": request.url,
            "status": resp.status,
            "latency_ms": resp.latency_ms,
            "error": resp.error,
            "timestamp": datetime.now().isoformat(),
        }
        self._save_history(entry)
        
        return resp
    
    def batch(self, requests: List[APIRequest], concurrency: int = 1) -> List[APIResponse]:
        """批量发送请求"""
        results = []
        for req in requests:
            results.append(self.send(req))
        return results
    
    def benchmark(self, url: str, count: int = 5, method: str = "GET") -> dict:
        """性能基准测试"""
        latencies = []
        errors = 0
        for i in range(count):
            req = APIRequest(method=method, url=url)
            resp = self.send(req)
            if resp.error:
                errors += 1
            else:
                latencies.append(resp.latency_ms)
        
        return {
            "url": url,
            "requests": count,
            "errors": errors,
            "latency": {
                "min": min(latencies) if latencies else None,
                "max": max(latencies) if latencies else None,
                "avg": round(sum(latencies) / len(latencies), 1) if latencies else None,
                "p50": sorted(latencies)[len(latencies)//2] if latencies else None,
                "p99": sorted(latencies)[int(len(latencies)*0.99)] if len(latencies) > 1 else None,
            },
            "timestamp": datetime.now().isoformat()
        }
    
    def graphql(self, endpoint: str, query: str, variables: dict = None) -> APIResponse:
        """发送GraphQL查询"""
        body = json.dumps({"query": query, "variables": variables or {}})
        req = APIRequest(
            method="POST",
            url=endpoint,
            body=body,
            content_type="application/json"
        )
        return self.send(req)
    
    def validate(self, resp: APIResponse, rules: Dict[str, Any]) -> List[str]:
        """验证响应是否符合规则"""
        failures = []
        
        if "status" in rules and resp.status != rules["status"]:
            failures.append(f"Status: expected {rules['status']}, got {resp.status}")
        
        if "header_contains" in rules:
            for key, val in rules["header_contains"].items():
                actual = resp.headers.get(key)
                if actual != val:
                    failures.append(f"Header {key}: expected '{val}', got '{actual}'")
        
        if "body_contains" in rules:
            for key in rules["body_contains"]:
                if resp.body_json and key not in resp.body_json:
                    failures.append(f"Body missing key: '{key}'")
        
        if "latency_max" in rules and resp.latency_ms > rules["latency_max"]:
            failures.append(f"Latency: {resp.latency_ms}ms > max {rules['latency_max']}ms")
        
        return failures
    
    def _save_history(self, entry: dict):
        entries = []
        if os.path.exists(self.history_file):
            with open(self.history_file, encoding="utf-8") as f:
                entries = json.load(f).get("tests", [])
        entries.append(entry)
        with open(self.history_file, "w", encoding="utf-8") as f:
            json.dump({"tests": entries}, f, ensure_ascii=False, indent=2)

# 使用示例
tester = APITester()

# 简单GET请求
req = APIRequest(method="GET", url="https://httpbin.org/get")
resp = tester.send(req)
print(f"GET {req.url} -> {resp.status} ({resp.latency_ms}ms)")
if resp.body_json:
    print(f"  Origin: {resp.body_json.get('origin', 'N/A')}")

# POST JSON
req2 = APIRequest(
    method="POST",
    url="https://httpbin.org/post",
    body=json.dumps({"name": "test", "value": 42}),
)
resp2 = tester.send(req2)
print(f"POST -> {resp2.status} ({resp2.latency_ms}ms)")

# GraphQL查询
gql_resp = tester.graphql(
    "https://api.github.com/graphql",
    "{ viewer { login } }"
)
print(f"GraphQL -> {gql_resp.status}")

# 性能基准
bench = tester.benchmark("https://httpbin.org/get", count=3)
print(f"基准: avg={bench['latency']['avg']}ms, errors={bench['errors']}")

# 验证
rules = {"status": 200, "latency_max": 3000}
failures = tester.validate(resp, rules)
print(f"验证: {'PASS' if not failures else 'FAIL: ' + str(failures)}")

常用验证规则

VALIDATION_RULES = {
    "health_check": {"status": 200, "latency_max": 500},
    "api_ok": {"status": 200, "body_contains": ["data", "status"]},
    "created": {"status": 201, "header_contains": {"Content-Type": "application/json"}},
    "no_content": {"status": 204},
    "redirect": {"status": 302},
    "unauthorized": {"status": 401},
    "not_found": {"status": 404},
    "server_error": {"status": 500, "latency_max": 5000},
}

使用场景

  1. CI/CD管道: 部署后自动测试API健康检查
  2. 接口文档: 自动生成API请求示例
  3. 性能回归: 每次部署后基准测试,发现性能退化
  4. 集成测试: 微服务间API契约验证

依赖

  • Python 3.8+
  • 标准库(urllib, json, time)
安全使用建议
Before installing, treat it like any API testing helper: do not put tokens or personal data in URLs unless needed, avoid testing internal systems unintentionally, and periodically delete api_tests.json if request history could reveal sensitive endpoint details.
能力评估
Purpose & Capability
The described capabilities, including REST/GraphQL requests, custom headers and bodies, response validation, benchmarking, and result persistence, match the stated API testing purpose.
Instruction Scope
The skill can send user-specified HTTP requests, including custom headers and bodies, but that is the core function of an API tester and the artifacts do not show hidden destinations or automatic unrelated network use.
Install Mechanism
The package contains a single non-executable SKILL.md file, no declared dependencies, no install scripts, and clean static/VirusTotal telemetry.
Credentials
Outbound network access and local file writes are proportionate for API testing, though users should be careful when testing internal endpoints or including secrets in URLs, headers, or bodies.
Persistence & Privilege
The artifact discloses test-result persistence and the code writes api_tests.json with method, URL, status, latency, error, and timestamp; it does not store headers, bodies, or response content, but URLs can still contain sensitive query data.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install laosi-api-tester
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /laosi-api-tester 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
laosi-api-tester 1.0.0 - Initial release of API Tester, a tool for sending and validating HTTP requests. - Supports GET/POST/PUT/DELETE requests and GraphQL queries. - Allows custom request headers, body, and content types. - Provides response validation (status, headers, body, latency), performance benchmarking, and result history persistence. - Suitable for CI/CD, API documentation, performance regression, and integration testing.
元数据
Slug laosi-api-tester
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

API接口测试 是什么?

API测试 - 构建/发送HTTP请求,验证响应状态码/头/体,性能基准(延迟/吞吐量),支持REST和GraphQL. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 25 次。

如何安装 API接口测试?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install laosi-api-tester」即可一键安装,无需额外配置。

API接口测试 是免费的吗?

是的,API接口测试 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

API接口测试 支持哪些平台?

API接口测试 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 API接口测试?

由 534422530(@534422530)开发并维护,当前版本 v1.0.0。

💬 留言讨论