Servicekit
Async SQLAlchemy framework with FastAPI integration - reusable foundation for building data services
Servicekit is a framework-agnostic core library providing foundational infrastructure for building async Python services with FastAPI and SQLAlchemy.
Features
- Database Layer: Async SQLAlchemy with SQLite support, connection pooling, and automatic migrations
- Repository Pattern: Generic repository base classes for data access
- Manager Pattern: Business logic layer with lifecycle hooks
- CRUD API: Auto-generated REST endpoints with full CRUD operations
- Authentication: API key middleware with file and environment variable support
- Job Scheduling: Async job scheduler with concurrency control
- App Hosting: Mount static web applications alongside your API
- Monitoring: Prometheus metrics and OpenTelemetry integration
- Health Checks: Flexible health check system with SSE streaming support
- Error Handling: RFC 9457 Problem Details for HTTP APIs
- Logging: Structured logging with request context
Installation
pip install servicekit
Quick Start
from servicekit.api import BaseServiceBuilder, ServiceInfo
app = (
BaseServiceBuilder(info=ServiceInfo(id="my-service", display_name="My Service"))
.with_health()
.with_database("sqlite+aiosqlite:///./data.db")
.build()
)
Architecture
servicekit/
├── database.py # Database, SqliteDatabase, SqliteDatabaseBuilder
├── models.py # Base, Entity ORM classes
├── repository.py # Repository, BaseRepository
├── manager.py # Manager, BaseManager
├── schemas.py # EntityIn, EntityOut, PaginatedResponse
├── scheduler.py # Scheduler, InMemoryScheduler
├── exceptions.py # Error classes
├── logging.py # Structured logging
├── types.py # ULIDType, JsonSafe
└── api/ # FastAPI framework layer
├── router.py # Router base class
├── crud.py # CrudRouter, CrudPermissions
├── auth.py # API key authentication
├── app.py # Static app hosting
├── middleware.py # Error handlers, logging
└── routers/ # Health, Jobs, System, Metrics
Key Components
BaseServiceBuilder
from servicekit.api import BaseServiceBuilder, ServiceInfo
app = (
BaseServiceBuilder(info=ServiceInfo(id="my-service", display_name="My Service"))
.with_health() # Health check endpoint
.with_database(url) # Database configuration
.with_jobs(max_concurrency=10) # Job scheduler
.with_auth() # API key authentication
.with_monitoring() # Prometheus metrics (on by default)
.with_app("./webapp") # Static web app
.include_router(custom_router) # Custom routes
.build()
)
Database Migrations
File-based databases run Alembic migrations on init() by default; in-memory databases create tables
directly from the ORM metadata. The migration bundled with servicekit is a framework baseline: it creates
only the alembic_version table and no application tables. Applications that define their own entities must
either point migrations at their own migration directory or disable migrations and create tables directly.
from pathlib import Path
from servicekit import SqliteDatabaseBuilder, get_alembic_dir
# Application-owned migrations
database = (
SqliteDatabaseBuilder.from_file("app.db")
.with_migrations(enabled=True, alembic_dir=Path("alembic"))
.build()
)
# No migrations - create tables directly from ORM metadata
database = SqliteDatabaseBuilder.from_file("app.db").with_migrations(enabled=False).build()
# Path to the migration environment shipped inside the servicekit package
bundled_migrations = get_alembic_dir()
Repository Pattern
from servicekit import BaseRepository, Entity
from sqlalchemy.orm import Mapped, mapped_column
class User(Entity):
__tablename__ = "users"
name: Mapped[str] = mapped_column()
email: Mapped[str] = mapped_column()
class UserRepository(BaseRepository[User, ULID]):
def __init__(self, session: AsyncSession):
super().__init__(session, User)
CRUD Router
from servicekit.api import CrudRouter, CrudPermissions
router = CrudRouter.create(
prefix="/api/v1/users",
tags=["Users"],
entity_in_type=UserIn,
entity_out_type=UserOut,
manager_factory=get_user_manager,
permissions=CrudPermissions(create=True, read=True, update=True, delete=False)
)
POST creates only and returns 409 Conflict for an ID that already exists or for any other database constraint
violation. PUT applies the fields sent: an omitted field keeps its value, an explicit null clears a nullable
field. Collection listings are ordered by ID, and pagination is opt-in through page (>= 1) and size (1-100),
which return 422 when out of range.
Examples
See the examples/ directory for complete working examples:
core_api/main.py- Basic CRUD servicejob_scheduler/main.py- Background job executionapp_hosting/main.py- Hosting static web appsauth/main.py- API key authenticationmonitoring/main.py- Prometheus metrics
Documentation
See docs/ for comprehensive guides and API reference.
Testing
make test # Run tests
make format # Format code and apply lint fixes
make lint # Check formatting, linting and types
make coverage # Test coverage
License
AGPL-3.0-or-later
Related Projects
Metadata
Release files for servicekit 3.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| servicekit-3.0.0.tar.gz | 51.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| servicekit-3.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 116.7 kB
Release files / servicekit-3.0.0.tar.gz
| Download URL | servicekit-3.0.0.tar.gz |
|---|---|
| Size | 51.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e0a2bdab02bc9ed697a9c7e7220ca883e740f430553f4f205cc36eec04813a5b
|
|
BLAKE2b-256 checksum How to use checksums |
ca19fa714df5ecddda7e4f6f0e68ea71121f9783986abb795c83ed72d7fb1c6e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / servicekit-3.0.0-py3-none-any.whl
| Download URL | servicekit-3.0.0-py3-none-any.whl |
|---|---|
| Size | 64.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
558e2dd0d4bde47ac6e18b53a70e0d83e6831d504d965c6f410db9f0a7dbdd76
|
|
BLAKE2b-256 checksum How to use checksums |
4813a34d4b1e3e8287784cfd6c03ee0f325f8fb98d2bab7b2c0b68468a8d6028
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log