Skip to content

Examples

This page provides links to complete code examples demonstrating common use cases.

Available Examples

All examples are located in the examples/ directory.

Basic Usage

File: examples/basic_usage.py

Demonstrates fundamental SDK operations:

  • Client initialization with JWT authentication
  • Listing folders and resources
  • Creating and updating folders
  • Proper client cleanup
from foxnose_sdk.management import ManagementClient
from foxnose_sdk.auth import JWTAuth

client = ManagementClient(
    base_url="https://api.foxnose.net",
    environment_key="your-environment-key",
    auth=JWTAuth.from_static_token("YOUR_ACCESS_TOKEN"),
)

# List all folders
folders = client.list_folders()
for folder in folders.results:
    print(f"{folder.name} ({folder.key})")

client.close()

Async Client

File: examples/async_client.py

Shows how to use the async client for concurrent operations:

  • AsyncManagementClient setup
  • Concurrent API calls with asyncio.gather()
  • Proper async context management
import asyncio
from foxnose_sdk.management import AsyncManagementClient

async def main():
    client = AsyncManagementClient(...)

    # Fetch multiple resources concurrently
    results = await asyncio.gather(
        client.get_folder("folder-1"),
        client.get_folder("folder-2"),
        client.list_resources("folder-3"),
    )

    await client.close()

asyncio.run(main())

Using Model Objects as Identifiers

Instead of extracting .key from every returned object, pass objects directly into subsequent calls:

# Get a folder object and use it directly
folder = client.get_folder("blog-posts")

# Pass the folder object — no need for folder.key
resources = client.list_resources(folder)

# Chain objects through a full workflow
resource = client.create_resource(folder, {"data": {"title": "New Article"}})
revision = client.create_revision(folder, resource, {
    "data": {"title": "Draft Content", "body": "..."},
})
client.publish_revision(folder, resource, revision)

# Works with all entity types
org = client.get_organization("org-key")
projects = client.list_projects(org)
project = projects.results[0]
envs = client.list_environments(org, project)

Resources and Revisions

File: examples/resources_and_revisions.py

Complete resource lifecycle management:

  • Creating resources
  • Managing revisions
  • Publishing content
  • Updating and deleting resources
# Create a resource
resource = client.create_resource("blog-posts", {
    "data": {"title": "My First Post", "content": "Hello, world!"},
})

# Create a new revision
revision = client.create_revision(
    "blog-posts",
    resource.key,
    {"data": {"title": "Updated Title", "content": "Updated content"}},
)

# Publish the revision
client.publish_revision("blog-posts", resource.key, revision.key)

Upsert (Create or Update by External ID)

Use upsert_resource to sync content from an external system. The SDK creates the resource on the first call and updates it on subsequent calls, matched by external_id.

articles = [
    {"id": "ext-1", "title": "First Article", "body": "..."},
    {"id": "ext-2", "title": "Second Article", "body": "..."},
]

for article in articles:
    resource = client.upsert_resource(
        "blog-posts",
        {"title": article["title"], "body": article["body"]},
        external_id=article["id"],
    )
    print(f"{resource.key} (external_id={resource.external_id})")

You can also set an external_id when creating resources via create_resource:

resource = client.create_resource(
    "blog-posts",
    {"title": "Imported Post"},
    external_id="legacy-post-99",
)

Batch Upsert

Use batch_upsert_resources to upsert many resources in parallel. This is much faster than calling upsert_resource in a loop:

from foxnose_sdk import ManagementClient, BatchUpsertItem

items = [
    BatchUpsertItem(
        external_id=f"article-{i}",
        payload={"title": f"Article {i}", "body": "..."},
    )
    for i in range(1000)
]

result = client.batch_upsert_resources(
    "blog-posts",
    items,
    max_concurrency=10,
    on_progress=lambda done, total: print(f"\r{done}/{total}", end=""),
)

print(f"\nSucceeded: {result.success_count}, Failed: {result.failure_count}")
for error in result.failed:
    print(f"  Item {error.index} ({error.external_id}): {error.exception}")

Folder Schema

File: examples/folder_schema.py

Schema and field management:

  • Creating schema versions
  • Adding and configuring fields
  • Publishing schema versions
  • Field type options
# Create a new schema version
version = client.create_folder_version("blog-posts", {"name": "v2.0"})

# Add fields
client.create_folder_field("blog-posts", version.key, {
    "key": "author",
    "name": "Author",
    "type": "text",
    "required": True,
})

# Publish the version
client.publish_folder_version("blog-posts", version.key)

Roles and Permissions

File: examples/roles_and_permissions.py

Access control configuration:

  • Creating management roles
  • Creating Flux roles
  • Setting permissions
  • Generating API keys
# Create a role
role = client.create_management_role({
    "name": "Content Editor",
    "description": "Can edit content but not delete",
})

# Add permissions
client.upsert_management_role_permission(role.key, {
    "content_type": "resources",
    "actions": ["read", "create", "update"],
    "all_objects": True,
})

# Create an API key with this role
api_key = client.create_management_api_key({
    "description": "Editor Key",
    "role": role.key,
})

Flux Client

File: examples/flux_client.py

Content delivery:

  • FluxClient initialization
  • Fetching published content
  • Search capabilities
  • Pagination and filtering
from foxnose_sdk.flux import FluxClient
from foxnose_sdk.auth import SimpleKeyAuth

client = FluxClient(
    base_url="https://<env_key>.fxns.io",
    api_prefix="v1",
    auth=SimpleKeyAuth("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY"),
)

# Get published content
resource = client.get_resource("blog-posts", "my-article")
print(resource["data"]["title"])

# Search for content
results = client.search("blog-posts", body={"find_text": {"query": "python"}})

File: examples/vector_search.py

Vector search modes and configuration:

  • Semantic search with auto-generated embeddings
  • Custom embedding search
  • Hybrid text + vector search
  • Boosted search with vector similarity
from foxnose_sdk.flux import FluxClient

# Semantic search
results = client.vector_search("blog-posts", query="machine learning")

# Hybrid search
results = client.hybrid_search(
    "blog-posts",
    query="ML applications",
    find_text={"query": "machine learning"},
    vector_weight=0.7,
    text_weight=0.3,
)

Running Examples

  1. Clone the repository:
git clone https://github.com/FoxNoseTech/foxnose-python.git
cd python-sdk
  1. Install dependencies:
pip install -e .
  1. Set environment variables:
export FOXNOSE_API_URL="https://api.foxnose.net"
export FOXNOSE_ENVIRONMENT_KEY="your-environment-key"
export FOXNOSE_ACCESS_TOKEN="your-access-token"
  1. Run an example:
python examples/basic_usage.py

Real-World Patterns

Environment-Based Configuration

import os
from foxnose_sdk.management import ManagementClient
from foxnose_sdk.auth import JWTAuth

def get_client():
    return ManagementClient(
        base_url=os.environ.get("FOXNOSE_API_URL", "https://api.foxnose.net"),
        environment_key=os.environ["FOXNOSE_ENVIRONMENT_KEY"],
        auth=JWTAuth.from_static_token(os.environ["FOXNOSE_ACCESS_TOKEN"]),
    )

Context Manager Pattern

from contextlib import contextmanager

@contextmanager
def foxnose_client():
    client = ManagementClient(...)
    try:
        yield client
    finally:
        client.close()

# Usage
with foxnose_client() as client:
    folders = client.list_folders()

Pagination Helper

def iter_all_resources(client, folder_key, page_size=50):
    """Iterate through all resources with automatic pagination."""
    offset = 0
    while True:
        page = client.list_resources(
            folder_key,
            params={"limit": page_size, "offset": offset},
        )
        yield from page.results

        if len(page.results) < page_size:
            break
        offset += page_size

# Usage
for resource in iter_all_resources(client, "blog-posts"):
    print(resource.title)