Skip to main content

A project generator that bootstraps a FastAPI setup following Helicon's standards and best practices.

Project description

Helicon kit

A project generator that bootstraps a FastAPI setup following Helicon's standards and best practices.

Included tools

These are the major tools that are configured and included in the project:

  • structlog
  • sqlmodel
  • alembic
  • fastapi
  • pydantic-settings
  • pytest

Start a new project

Run the following commands to initialize a new project:

mkdir helicon-app
cd helicon-app
uvx he-kit init

After answering the prompts you should have a fully runnable FastAPI setup:

├── .dockerignore
├── .gitignore
├── .pre-commit-config.yaml
├── alembic.ini
├── Dockerfile
├── main.py
├── pyproject.toml
├── README.md
├── migrations
│   ├── env.py
│   ├── script.py.mako
│   └── versions
├── src
│   └── helicon_app
│       ├── app.py
│       ├── conf.py
│       ├── __init__.py
│       ├── models
│       │   └── __init__.py
│       ├── routers
│       │   └── __init__.py
│       └── schemas
│           └── __init__.py
└── tests
    └── conftest.py

You can verify that it works by running the test suite and starting the development server:

uv run pytest
uv run he-kit dev

It is recommended that you synchronize the new environment and install the supplied pre-commit hooks (mypy and ruff):

uv sync
uv run pre-commit install

Create a model and migrations

Helicon-kit uses SQLModel and Alembic. To start working with models, first create a new module in the models/ directory. We'll call it models/users.py:

from sqlmodel import Field, SQLModel


class User(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    email: str

We have to make sure the models are importable via your_module_name.models in order for Alembic to discover them. We do this by importing the new module in models/__init__.py:

from .users import *

Create the migrations and apply them:

uv run he-kit makemigrations "add user model"
uv run he-kit migrate

Create and register a new router

Firstly we need to define some API schemas. We'll add them in the module schemas/users.py:

from sqlmodel import SQLModel


class UserCreate(SQLModel):
    name: str
    email: str


class UserRead(SQLModel):
    id: int
    name: str
    email: str

Note: as both schemas and models are derrived from SQLModel you can of course create base classes and extend them to avoid repeating attributes.

We'll continue and a new module in the routers/ directory. We'll stay on the theme and call it routers/users.py:

from he_kit.core.db import db_session
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select

from ..models.users import User
from ..schemas.users import UserCreate, UserRead

router = APIRouter()


@router.get("/", response_model=list[UserRead])
async def list_users(session: AsyncSession = Depends(db_session)):
    result = await session.execute(select(User))
    users = result.scalars().all()
    return users


@router.post("/", response_model=UserRead)
async def create_user(user: UserCreate, session: AsyncSession = Depends(db_session)):
    user = User.model_validate(user)
    session.add(user)
    await session.commit()
    await session.refresh(user)
    return user

And finally we register the router in app.py:

from he_kit.core.app import App

from .conf import settings
from .routers.users import router as user_router


def create_app():
    app = App(settings=settings)

    app.include_router(user_router, prefix="/users")

    return app


app = create_app()

Writing tests

To verify that everything works we'll create a testmodule in tests/test_user_endpoints.py:

def test_create_user(client):
    payload = {"name": "Alice", "email": "alice@example.com"}
    r = client.post("/users/", json=payload)
    assert r.status_code == 200
    data = r.json()
    assert data["name"] == "Alice"
    assert data["email"] == "alice@example.com"
    assert "id" in data


def test_list_users(client):
    payload = {"name": "Bob", "email": "bob@example.com"}
    r = client.post("/users/", json=payload)
    assert r.status_code == 200

    r = client.get("/users/")
    assert r.status_code == 200
    users = r.json()
    assert any(u["name"] == "Bob" for u in users)

Save the file and run the tests suite:

uv run pytest

Local development setup

To install he-kit from local disk to try it out during development, you can install it with pip:

mkdir test-dir
cd test-dir
uv venv
pip install -e ../path/to/he-kit
uv run he-kit ...

Keycloak authentication

he-kit support Keycloak as an optional authentication backend.

Installation

Keycloak support is provided via an optional dependency.

uv add he-kit[keycloak]

Configuration

Enable the Keycloak backend by setting AUTH_BACKEND to the fully qualified provider path and supplying AUTH_BACKEND_SETTINGS as a KeycloakSettings instance.

from he_kit.core.conf import DefaultSettings
from he_kit.authn.keycloak import KeycloakSettings

settings = DefaultSettings(
    AUTH_BACKEND="he_kit.authn.keycloak.KeycloakAuthProvider",
    AUTH_BACKEND_SETTINGS=KeycloakSettings(
        SERVER_URL="http://localhost:8080",
        REALM="my-realm",
        CLIENT_ID="api-client",
        CLIENT_SECRET="secret",
        ADMIN_USERNAME="admin",
        ADMIN_PASSWORD="admin",
    ),
)

Releasing a new version

Update the version in the pyproject.toml file, commit it, create a matching tag in git, and push:

git tag v0.1.x
git push --tags

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

he_kit-0.0.17.tar.gz (108.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

he_kit-0.0.17-py3-none-any.whl (24.5 kB view details)

Uploaded Python 3

File details

Details for the file he_kit-0.0.17.tar.gz.

File metadata

  • Download URL: he_kit-0.0.17.tar.gz
  • Upload date:
  • Size: 108.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for he_kit-0.0.17.tar.gz
Algorithm Hash digest
SHA256 0f2057948d9759fcbee63e1523b865dca59e65e1c7ffadb5e411a989455f040e
MD5 db54a11aaa77e3f1e8a46cb987924e9c
BLAKE2b-256 f2065b02b298779fd1dc4392f545e7d21f0cffa5caa6b17b4e99b28da637b2c8

See more details on using hashes here.

File details

Details for the file he_kit-0.0.17-py3-none-any.whl.

File metadata

  • Download URL: he_kit-0.0.17-py3-none-any.whl
  • Upload date:
  • Size: 24.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for he_kit-0.0.17-py3-none-any.whl
Algorithm Hash digest
SHA256 e169566d2569837f8ff352102929b555b1f32ecc85aa99e696e40ad3b51358e5
MD5 a274085c858dbe29faf726e8c4a88130
BLAKE2b-256 2bd2f5d11f9fb5664a83ecc5f35a2138968b9ba9b87302939ebefd55402311e4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page