Install
$ agentstack add skill-knuckles-team-universal-skills-api-client-builder ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
API Client Builder
This skill provides step-by-step guidance on how to build a robust, standardized API client for our Pydantic AI agents. It supports both REST (using requests) and GraphQL (using gql) APIs, with Pydantic models and decorators from agent_utilities.
Standard API Client Structure
All API clients MUST use the api/ subdirectory pattern (the monolithic api_client.py single-file approach is deprecated):
{pkg_dir}/
├── auth.py # Authentication setup
├── api_client.py # Facade re-exporting from api/ (backward compat)
├── models.py # Pydantic input/output models
├── api/
│ ├── __init__.py # Expose ApiClientBase + all domain clients
│ ├── api_client_base.py # HTTP handler base class
│ └── api_client_{domain}.py # Domain-specific API methods
└── gql_client.py # Optional: GraphQL client
Creating an API Client
1. Analyze the API Output/Input
Review the provided API documentation (OpenAPI JSON/YAML, developer guides). Identify endpoints, authentication methods, request parameters, and response schemas. Determine if the API supports GraphQL (create both REST + GraphQL clients if so).
> [!IMPORTANT] > Wrap the WHOLE API — no stubs. These repos exist to fully wrap their service's > API; the MCP layer is a thin shim on top. A class DomainClient: pass placeholder is > not acceptable (the jena/kafka/camunda/archi rebuilds replaced exactly such stubs). > Enumerate every endpoint group the service exposes and implement a method for each — > e.g. Apache Jena Fuseki = SPARQL query/update + Graph Store Protocol + the /$/ admin > API (datasets, stats, tasks, backup, compact); Kafka REST Proxy = clusters/topics/ > partitions/records/consumer-groups/brokers/ACLs. Coverage is auditable via > scripts/verify_api_integration.py; a near-zero score means the wrapper is a stub. > Keep heavy/native client libraries (e.g. confluent-kafka) as optional extras and > import them lazily so the wheel build never depends on a C toolchain.
2. Formulate Pydantic Models
Create {pkg_dir}/models.py:
- Input Models: Pydantic models for API request parameters and bodies (include
page_token/limitfor pagination) - Response Models: Pydantic models to parse and validate JSON responses
- Use
references/api_models_template.py.templatefor reference
3. Create the API Client Class Structure
{pkg_dir}/api/api_client_base.py
- Inherits from a base HTTP handler or constructs a base client using
requests.Session() - Configures TLS verification, proxies, headers, base URL, and low-level HTTP calls (
_request,get,post, etc.) - Reads auth credentials from standard env vars
{pkg_dir}/api/api_client_{domain}.py
- Inherits from
ApiClientBase - Exposes pythonic methods mapping directly to target service endpoint actions
- One file per functional domain (e.g.,
api_client_docker.py,api_client_system.py)
{pkg_dir}/api/__init__.py
- Exposes all classes for clean imports:
from {pkg_dir}.api import ApiClientBase, ApiClientDocker
{pkg_dir}/api_client.py (Facade)
- Re-exports from
api/for backward compatibility:
``python from {pkg_dir}.api import ApiClientBase, ApiClientSystem # noqa: F401 ``
4. Implement Methods and Decorators
For each endpoint:
- Unpack arguments using Pydantic models (
Model(**kwargs)) - Check required parameters — raise
agent_utilities.exceptions.MissingParameterErrorif absent - Use
@require_authdecorator fromagent_utilities.decoratorson authenticated methods - Make HTTP requests using the initialized session
- Parse JSON responses with appropriate Pydantic response model
- Handle errors: 401/403 →
AuthError/UnauthorizedError, invalid params →ParameterError - Return standard response objects
5. Create GraphQL Client (Optional)
If the target API supports GraphQL, create {pkg_dir}/gql_client.py:
- Use
gql.Clientwithgql.transport.requests.RequestsHTTPTransport - Implement
execute_gql(query_str, variables, operation_name)for raw query execution - Mirror REST methods with GraphQL equivalents
- Use cursor-based pagination (
first/after) - Apply
@require_authdecorator - Add
gql = ["gql>=4.0.0"]to pyproject.toml optional dependencies - Register as optional module with
_GQL_AVAILABLEflag in__init__.py
6. Configure Authentication (auth.py)
Standard environment variable naming:
| Pattern | Example | Notes | |---------|---------|-------| | {SERVICE}_URL | PORTAINER_URL | NOT _BASE_URL or _INSTANCE | | {SERVICE}_TOKEN | PORTAINER_TOKEN | Prefer over _API_KEY | | {SERVICE}_SSL_VERIFY | PORTAINER_SSL_VERIFY | NOT _VERIFY or _AGENT_VERIFY | | {SERVICE}_USERNAME | PORTAINER_USERNAME | For basic auth | | {SERVICE}_PASSWORD | PORTAINER_PASSWORD | For basic auth |
First-party env vars: Preserve names when the upstream service defines them (e.g., GITHUB_TOKEN, LANGFUSE_PUBLIC_KEY).
Standard auth.py pattern:
import os
from {pkg_dir}.api import ApiClient{Domain}
def get_client() -> ApiClient{Domain}:
"""Initialize authenticated API client."""
try:
return ApiClient{Domain}(
url=os.getenv("{SERVICE}_URL", ""),
token=os.getenv("{SERVICE}_TOKEN", ""),
ssl_verify=os.getenv("{SERVICE}_SSL_VERIFY", "True").lower() in ("true", "1", "yes"),
)
except Exception as e:
raise RuntimeError(f"Failed to initialize {service} client: {e}") from e
Referencing the Templates
| Template | Purpose | |----------|---------| | api_client_template.py.template | REST API client class | | api_models_template.py.template | Pydantic input/output models | | api_graphql_template.py.template | GraphQL API client class |
Ecosystem Drift Check (MANDATORY)
After completing the API client, run a drift audit to confirm the project meets all ecosystem standards. This is a hard gate — the package is not complete until it passes with 0 missing items.
cd {project_dir} && echo "=== Drift Audit ===" \
&& for f in README.md CHANGELOG.md AGENTS.md pyproject.toml requirements.txt \
.pre-commit-config.yaml .bumpversion.cfg .gitignore .gitattributes \
.dockerignore .env; do \
[ -f "$f" ] && echo "✅ $f" || echo "❌ $f MISSING"; done \
&& for f in docs/index.md docs/overview.md docs/concepts.md; do \
[ -f "$f" ] && echo "✅ $f" || echo "❌ $f MISSING"; done \
&& for f in tests/conftest.py tests/test_concept_parity.py \
tests/test_init_dynamics.py tests/test_startup.py; do \
[ -f "$f" ] && echo "✅ $f" || echo "❌ $f MISSING"; done \
&& grep -q "ECO-4.0" docs/concepts.md && echo "✅ ECO-4.0 bridge" \
|| echo "❌ ECO-4.0 bridge MISSING"
> [!IMPORTANT] > A new package is not complete until it passes the drift check with 0 missing items.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Knuckles-Team
- Source: Knuckles-Team/universal-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.