Skip to main content

🐍 Chilo

Chilo

Chilo is a lightweight, form-meets-function, opinionated (yet highly configurable) API framework.

CircleCI Quality Gate Status Coverage Bugs PyPI Python Inline docs Contributions welcome

Chilo (short for chilorhinophis, the two-headed snake) auto-routes requests straight from your directory tree, applies OpenAPI or custom validation before your handlers run, and keeps REST + gRPC services declarative and composable.


📖 Documentation & Examples

Full Documentation · Examples · Community Discussions


🎯 Why Chilo?

  • 🚀 Zero Route Boilerplate – File paths become URLs; dynamic segments are inferred from file names.
  • ✅ Built-in Validation – Apply OpenAPI schemas (request + response) or lightweight requirement decorators.
  • 🧱 Middlewares Everywhere – before, after, when_auth_required, and global hooks keep cross-cutting logic centralized.
  • 🔔 Lifecycle Hooks – on_startup / on_shutdown let you register callables that fire once when the router boots and when it stops.
  • 🔁 REST + gRPC – Switch between HTTP and gRPC by flipping api_type and pointing at protobufs.
  • 📜 Spec Generation – Inspect handlers + requirements to emit openapi.yml/openapi.json with a single CLI command.
  • ⚙️ Deploy-Friendly – Works with gunicorn or the built-in CLI; supports TLS, CORS, hot reload, and custom executors.

Happy Path Programming

Validate the world up front, then write business logic as if everything is already correct.

# ❌ Without Chilo
def handler(environ, start_response):
    body = json.loads(environ.get('body') or '{}')
    if 'email' not in body:
        return error(400, 'email required')
    if '@' not in body['email']:
        return error(400, 'invalid email')
    # more guards ...
    return ok({'user': create(body)})
# ✅ With Chilo
from chilo_api import requirements, Request, Response

@requirements(required_body='v1-create-user')
def post(request: Request, response: Response) -> Response:
    response.body = {'user': create(request.body)}  # already validated
    return response

📦 Installation

pip install chilo_api
# pipenv install chilo_api
# poetry add chilo_api

Supports Python 3.8


🚀 Quick Start · REST

1. Configure the API (e.g., api/main.py)

from chilo_api import Chilo
from chilo_api import logger


def cleanup_connections():
    # close DB pools, flush caches, etc.
    pass

api = Chilo(
    base_path='/',
    handlers='api/handlers',
    cors=True,
    on_startup=[lambda: logger.log(level='INFO', log='API booted')],
    on_shutdown=[cleanup_connections],
    openapi='api/openapi.yml',      # optional
    openapi_validate_request=False, # flip on when ready
    openapi_validate_response=False
)

2. Create a Handler (api/handlers/__init__.py)

from chilo_api import Request, Response, requirements

@requirements(required_query=['greeting'])
def get(request: Request, response: Response) -> Response:
    response.body = {'hello': request.query_params['greeting']}
    return response

3. Run It

python -m chilo_api serve --api=api.main --reload=true

Visit http://127.0.0.1:3000/?greeting=developer

Directory → Route Mapping

api/handlers
├── __init__.py          → /
├── user/__init__.py     → /user
├── user/_user_id.py     → /user/{user_id}
└── reports/daily.py     → /reports/daily

Dynamic segments are prefixed with _ in file names (or directories) and become {param} tokens at runtime.


📡 Quick Start · gRPC

1. Define the API (api/main_grpc.py)

from chilo_api import Chilo

api = Chilo(
    api_type='grpc',
    handlers='api/handlers',
    protobufs='api/protobufs',
    reflection=True,
    port=50051
)

2. Author Your Proto (api/protobufs/calculator.proto)

syntax = "proto3";
package calculator;

service Calculator {
    rpc Add(CalcRequest) returns (CalcResponse);
}

message CalcRequest { double num1 = 1; double num2 = 2; }
message CalcResponse { double result = 1; }

3. Implement the Handler (api/handlers/__init__.py)

from chilo_api import requirements, Request, Response

@requirements(protobuf='calculator.proto', service='Calculator', rpc='Add')
def add(request: Request, response: Response) -> Response:
    response.body = {'result': request.body.get('num1', 0) + request.body.get('num2', 0)}
    return response

4. Serve It

python -m chilo_api serve --api=api.main_grpc

🧰 CLI Highlights

Command Description
python -m chilo_api serve --api=api.main Run REST or gRPC servers with hot reload, TLS, verbose logging, etc.
python -m chilo_api generate-openapi --api=api.main --output=docs --format=yml,json Inspect handlers + requirements to (re)build OpenAPI docs.

Both commands accept switches for host, port, reload, private key/cert, worker count, and validation flags.


🤝 Contributing

Issues and PRs are welcome! Check SECURITY.md before reporting vulnerabilities and open a discussion if you want to propose larger features. For docs fixes, see chilo-docs.


📜 License

Chilo is released under the MIT License.

Metadata

Release files for chilo-api 2.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chilo-api 2.0.2
File Size Uploaded
chilo_api-2.0.2.tar.gz 84.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for chilo-api 2.0.2
File Interpreter ABI Platform
chilo_api-2.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 198.7 kB

Release files / chilo_api-2.0.2.tar.gz

Download URL chilo_api-2.0.2.tar.gz
Size 84.3 kB
Tags Source
SHA-256 checksum
How to use checksums
eaf097ffd5a35ce3e026fa7280a77c45a1a6eed6718aaee21c3a8cfc201f2ee9
BLAKE2b-256 checksum
How to use checksums
aa0309c8a223ad8753a1ea5f05bfa9be8733f08cbe4c04d3979697fb25f550a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.17

Release files / chilo_api-2.0.2-py3-none-any.whl

Download URL chilo_api-2.0.2-py3-none-any.whl
Size 114.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dc7dec4de04a86d1cc9edc3fcb33b7e98c221ded905b26d5c8b4284f4675dc86
BLAKE2b-256 checksum
How to use checksums
f3c064ea78938feecd1e95bc703d4b397ed6d4a75ee426f5766e951c7ba7793c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.17
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page