Metadata-Version: 2.4
Name: llamaapi-llamasearch
Version: 0.1.0
Summary: A flexible API client and server utilities package
Home-page: https://llamasearch.ai
Author: LlamaSearch AI
Author-email: nikjois@llamasearch.ai
Project-URL: Bug Tracker, https://github.com/llamasearch/llamaapi/issues
Project-URL: Documentation, https://llamasearch.ai/docs/llamaapi
Project-URL: Source Code, https://github.com/llamasearch/llamaapi
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Requires-Dist: pydantic>=1.9.0
Requires-Dist: PyYAML>=6.0
Requires-Dist: redis>=4.3.4
Requires-Dist: ujson>=5.4.0
Requires-Dist: httpx>=0.23.0
Requires-Dist: marshmallow>=3.17.0
Requires-Dist: openapi-spec-validator>=0.4.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
Requires-Dist: black>=22.6.0; extra == "dev"
Requires-Dist: isort>=5.10.1; extra == "dev"
Requires-Dist: mypy>=0.971; extra == "dev"
Requires-Dist: flake8>=5.0.4; extra == "dev"
Provides-Extra: server
Requires-Dist: flask>=2.2.0; extra == "server"
Requires-Dist: fastapi>=0.85.0; extra == "server"
Requires-Dist: uvicorn>=0.18.3; extra == "server"
Provides-Extra: auth
Requires-Dist: pyjwt>=2.4.0; extra == "auth"
Requires-Dist: cryptography>=37.0.4; extra == "auth"
Provides-Extra: cache
Requires-Dist: cachetools>=5.2.0; extra == "cache"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.4.0; extra == "docs"
Requires-Dist: mkdocs-material>=8.5.0; extra == "docs"
Requires-Dist: mkdocstrings>=0.19.0; extra == "docs"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license-file
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# LlamaAPI

Flexible API client and server utilities for LlamaSearch.ai applications.

## Features

### API Client

- **Flexible Authentication**: Support for API keys, Bearer tokens, Basic auth, and OAuth2
- **Middleware Pipeline**: Customize request/response handling with middleware
- **Caching**: Built-in caching system with memory, file, and Redis backends
- **Error Handling**: Comprehensive error types and handling
- **Retry Logic**: Automatic retry with configurable backoff strategies
- **Streaming Support**: Efficient handling of large data streams
- **Rate Limiting**: Client-side rate limiting to avoid API throttling

### API Server

- **Route Management**: Easy-to-use decorators for defining API routes
- **Request Validation**: JSON schema validation for requests
- **Middleware Support**: Global and route-specific middleware
- **Error Handling**: Comprehensive error handling with custom handlers
- **Authentication**: Built-in authentication utilities
- **CORS Support**: Simple CORS configuration
- **Async Support**: First-class support for async/await

## Installation

```bash
pip install llamaapi
```

## Client Example

```python
from llamaapi import create_client, ApiKeyAuth, LoggingMiddleware

# Create API client with API key authentication
client = create_client(
    base_url="https://api.example.com/v1",
    auth=ApiKeyAuth("your-api-key"),
    middleware=[LoggingMiddleware()],
    timeout=10,
    retries=3,
)

# Make GET request
response = client.get("users")
response.raise_for_status()
users = response.json()
print(f"Found {len(users)} users")

# Make POST request
new_user = {"name": "John Doe", "email": "john.doe@example.com"}
response = client.post("users", json=new_user)
response.raise_for_status()
created_user = response.json()
print(f"Created user: {created_user['name']}")
```

## Server Example

```python
from llamaapi import create_api, Request, Response, HttpMethod

# Create API instance
api = create_api(name="My API", version="1.0.0")

# Define a route
@api.route("/users", methods=HttpMethod.GET)
async def get_users(request: Request) -> Response:
    # Get data from your data source
    users = [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]
    return Response().with_json(users)

# Define a route with path parameters
@api.route("/users/{user_id}", methods=HttpMethod.GET)
async def get_user(request: Request) -> Response:
    user_id = request.path_params.get("user_id")
    
    # Get user data from your data source
    user = {"id": user_id, "name": "John Doe"}
    
    return Response().with_json(user)
```

For more detailed examples, see the `examples` directory.

## Authentication

### API Key Auth

```python
from llamaapi import create_client, ApiKeyAuth

client = create_client(
    base_url="https://api.example.com",
    auth=ApiKeyAuth(api_key="your-api-key"),
)
```

### Bearer Token Auth

```python
from llamaapi import create_client, BearerAuth

client = create_client(
    base_url="https://api.example.com",
    auth=BearerAuth(token="your-token"),
)
```

### OAuth2 Auth

```python
from llamaapi import create_client, OAuth2Auth

auth = OAuth2Auth(
    token_url="https://auth.example.com/oauth/token",
    client_id="your-client-id",
    client_secret="your-client-secret",
    scope="read write",
)

# Use client credentials flow to get a token
auth.client_credentials_flow()

client = create_client(
    base_url="https://api.example.com",
    auth=auth,
)
```

## Advanced Client Features

### Middleware

```python
from llamaapi import (
    create_client, 
    LoggingMiddleware, 
    RetryMiddleware, 
    HeadersMiddleware,
)

middleware = [
    LoggingMiddleware(log_headers=True),
    RetryMiddleware(max_retries=3),
    HeadersMiddleware({"User-Agent": "MyApp/1.0"}),
]

client = create_client(
    base_url="https://api.example.com",
    middleware=middleware,
)
```

### Caching

```python
from llamaapi import create_client, MemoryCache, FileCache

# Memory cache
client = create_client(
    base_url="https://api.example.com",
    cache=MemoryCache(max_size=100),
)

# File cache
client = create_client(
    base_url="https://api.example.com",
    cache=FileCache(cache_dir=".cache"),
)
```

### Streaming

```python
from llamaapi import create_client

client = create_client(base_url="https://api.example.com")

# Stream large data
with client.stream("GET", "large-dataset") as response:
    for chunk in response.iter_content(chunk_size=1024):
        process_chunk(chunk)
```

## Advanced Server Features

### Request Validation

```python
from llamaapi import api, validate_json_schema

user_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "minLength": 2},
        "email": {"type": "string", "format": "email"},
    },
    "required": ["name", "email"],
}

@api.route(
    "/users", 
    methods=HttpMethod.POST,
    middleware=[validate_json_schema(user_schema)]
)
async def create_user(request: Request) -> Response:
    user_data = request.json()
    # Create user with validated data
    return Response(status_code=201).with_json(new_user)
```

### Authentication

```python
from llamaapi import api, require_auth

# Define authentication middleware
async def auth_middleware(request: Request) -> Request:
    api_key = request.headers.get("X-API-Key")
    if api_key == "secret-key":
        request.context["user"] = {"id": "admin", "role": "admin"}
    return request

api.add_middleware(auth_middleware)

# Require authentication for specific routes
@api.route("/admin-only", methods=HttpMethod.GET)
@require_auth
async def admin_only(request: Request) -> Response:
    user = request.context["user"]  # This is guaranteed to exist
    return Response().with_json({"message": f"Hello, {user['id']}"})
```

## License

MIT License 
