Skip to content

Commit 303f31c

Browse files
authored
Merge pull request #79 from akhundMurad/feat/integrations
feat(docs): add framework integrations and improve documentation structure
2 parents 7c2640e + 13b9792 commit 303f31c

39 files changed

Lines changed: 1283 additions & 435 deletions

.github/workflows/pr.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323

2424
- name: Sync dependencies (locked)
2525
run: |
26-
uv sync --locked --all-groups
26+
uv sync --locked --all-groups --all-extras
2727
2828
- name: Build & install native extension (maturin develop)
2929
uses: PyO3/maturin-action@v1
@@ -55,7 +55,7 @@ jobs:
5555

5656
- name: Sync dependencies (locked)
5757
run: |
58-
uv sync --locked --all-groups
58+
uv sync --locked --all-groups --all-extras
5959
6060
- name: Build & install native extension (maturin develop)
6161
uses: PyO3/maturin-action@v1

README.md

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# TypeID Python
22

3-
[![Run Tests](https://github.com/akhundMurad/typeid-python/actions/workflows/test.yml/badge.svg)](https://github.com/akhundMurad/typeid-python/actions/workflows/test.yml)
4-
[![PyPI Downloads](https://static.pepy.tech/personalized-badge/typeid-python?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/typeid-python)
53
[![PyPI - Version](https://img.shields.io/pypi/v/typeid-python?color=green)](https://pypi.org/project/typeid-python/)
64
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/typeid-python?color=green)](https://pypi.org/project/typeid-python/)
5+
[![PyPI Downloads](https://static.pepy.tech/personalized-badge/typeid-python?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/typeid-python)
6+
![GitHub License](https://img.shields.io/github/license/akhundMurad/typeid-python)
77

8+
> [!WARNING]
9+
> `main` may contain unreleased changes. For stable usage, use the latest release tag.
810
911
A **high-performance Python implementation of [TypeIDs](https://github.com/jetpack-io/typeid)** — type-safe,
1012
sortable identifiers based on **UUIDv7**.
@@ -21,11 +23,12 @@ This library provides a Python package with Rust acceleration.
2123
## Key features
2224

2325
- ✅ UUIDv7-based, time-sortable identifiers
24-
- ✅ Type-safe prefixes (`user_`, `order_`, …)
25-
- ✅ Human-readable and URL-safe
26+
- ✅ Schema-based ID explanations (JSON / YAML)
2627
- ✅ Fast generation & parsing (Rust-accelerated)
28+
- ✅ Multiple integrations (Pydantic, FastAPI, ...)
29+
- ✅ Type-safe prefixes (`user_`, `order_`, ...)
30+
- ✅ Human-readable and URL-safe
2731
- ✅ CLI tools (`new`, `encode`, `decode`, `explain`)
28-
- ✅ Schema-based ID explanations (JSON / YAML)
2932
- ✅ Fully offline, no external services
3033

3134
## Performance
@@ -70,8 +73,9 @@ Included:
7073
### Other optional extras
7174

7275
```console
73-
$ pip install typeid-python[yaml] # YAML schema support
74-
$ pip install typeid-python[cli] # CLI tools
76+
$ pip install typeid-python[yaml] # YAML schema support
77+
$ pip install typeid-python[cli] # CLI tools
78+
$ pip install typeid-python[pydantic] # Pydantic integration
7579
```
7680

7781
Extras are **strictly optional**.
@@ -149,6 +153,45 @@ Encode:
149153
$ typeid encode 0188bac7-4afa-78aa-bc3b-bd1eef28d881 --prefix user
150154
```
151155

156+
## Framework integrations
157+
158+
TypeID is **framework-agnostic by design**.
159+
Integrations are provided as optional adapters, installed explicitly and kept separate from the core.
160+
161+
### Available integrations
162+
163+
* **Pydantic (v2)**
164+
Native field type with validation and JSON Schema support.
165+
166+
```bash
167+
pip install typeid-python[pydantic]
168+
```
169+
170+
```python
171+
from typing import Literal
172+
from pydantic import BaseModel
173+
from typeid.integrations.pydantic import TypeIDField
174+
175+
class User(BaseModel):
176+
id: TypeIDField[Literal["user"]]
177+
```
178+
179+
* **FastAPI**
180+
Works automatically via Pydantic (request/response models, OpenAPI).
181+
182+
```bash
183+
pip install typeid-python[fastapi]
184+
```
185+
186+
* **SQLAlchemy**
187+
Column types for storing TypeIDs (typically as strings).
188+
189+
```bash
190+
pip install typeid-python[sqlalchemy]
191+
```
192+
193+
All integrations are **opt-in via extras** and never affect the core package.
194+
152195
## `typeid explain` — understand any ID
153196

154197
```console

docs/integrations/index.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Framework Integrations
2+
3+
TypeID is designed to be framework-agnostic.
4+
The core package does not depend on any web framework, ORM, or serialization library.
5+
6+
Integrations are provided as **optional** adapters that translate between TypeID and specific ecosystems.
7+
They are installed explicitly and never affect the core unless imported.
8+
9+
---
10+
11+
## Available integrations
12+
13+
### Pydantic (v2)
14+
15+
Native support for using TypeID in Pydantic v2 models.
16+
17+
* Prefix-aware validation
18+
* Accepts `str` and `TypeID`
19+
* Serializes as string
20+
* Clean JSON Schema / OpenAPI output
21+
22+
```bash
23+
pip install typeid-python[pydantic]
24+
```
25+
26+
See: [Pydantic v2](https://akhundmurad.github.io/typeid-python/integrations/pydantic/) documentation page for details and examples.
27+
28+
### FastAPI
29+
30+
FastAPI builds on Pydantic v2, so TypeID works automatically in:
31+
32+
* request models
33+
* response models
34+
* OpenAPI schemas
35+
36+
No separate FastAPI-specific adapter is required.
37+
38+
```bash
39+
pip install typeid-python[fastapi]
40+
```
41+
42+
See: [Pydantic v2](https://akhundmurad.github.io/typeid-python/integrations/fastapi/) documentation page for details and examples.
43+
44+
### SQLAlchemy
45+
46+
Column types for storing TypeIDs in relational databases.
47+
48+
Typical usage stores the full TypeID string (`prefix_suffix`) for clarity and debuggability.
49+
50+
```bash
51+
pip install typeid-python[sqlalchemy]
52+
```
53+
54+
See: [Pydantic v2](https://akhundmurad.github.io/typeid-python/integrations/sqlalchemy/) documentation page for details and examples.
55+
56+
## Design notes
57+
58+
* The TypeID core never imports framework code
59+
* Validation rules live in the core, not in adapters
60+
* Integrations are thin and easy to replace or extend
61+
62+
This keeps the library stable even as frameworks evolve.
63+
64+
## Adding new integrations
65+
66+
If you want to integrate TypeID with another framework:
67+
68+
* keep the adapter small,
69+
* avoid duplicating validation logic,
70+
* depend on the TypeID core as the single source of truth.
71+
72+
Community integrations are welcome.

docs/integrations/pydantic.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Pydantic v2 integration
2+
3+
TypeID ships with an **optional Pydantic v2 adapter**.
4+
It lets you use `TypeID` in Pydantic models without pulling Pydantic into the TypeID core.
5+
6+
The adapter:
7+
8+
* validates values using the TypeID core,
9+
* optionally enforces a fixed prefix,
10+
* serializes TypeIDs as strings,
11+
* exposes sensible JSON Schema metadata.
12+
13+
---
14+
15+
## Installation
16+
17+
```bash
18+
pip install typeid-python[pydantic]
19+
```
20+
21+
This installs the latest version of Pydantic v2.
22+
23+
## Basic usage
24+
25+
Use `TypeIDField` with a fixed prefix.
26+
27+
```python
28+
from typing import Literal
29+
from pydantic import BaseModel
30+
from typeid.integrations.pydantic import TypeIDField
31+
32+
class User(BaseModel):
33+
id: TypeIDField[Literal["user"]]
34+
35+
u = User(id="user_01ke82dtesfn9bjcrzyzz54ya9")
36+
assert str(u.id) == "user_01ke82dtesfn9bjcrzyzz54ya9"
37+
```
38+
39+
## Accepted inputs
40+
41+
You can pass either a string or a `TypeID` instance.
42+
43+
```python
44+
from typing import Literal
45+
from pydantic import BaseModel
46+
from typeid.integrations.pydantic import TypeIDField
47+
48+
class User(BaseModel):
49+
id: TypeIDField[Literal["user"]]
50+
51+
u = User(id="user_01ke82dtesfn9bjcrzyzz54ya9")
52+
assert u.id is not None
53+
```
54+
55+
```python
56+
from typing import Literal
57+
from pydantic import BaseModel
58+
from typeid import TypeID
59+
from typeid.integrations.pydantic import TypeIDField
60+
61+
class User(BaseModel):
62+
id: TypeIDField[Literal["user"]]
63+
64+
tid = TypeID.from_string("user_01ke82dtesfn9bjcrzyzz54ya9")
65+
u = User(id=tid)
66+
67+
assert u.id == tid
68+
```
69+
70+
In both cases, `id` is stored as a `TypeID` object inside the model.
71+
72+
## Prefix validation
73+
74+
The prefix in `TypeIDField[...]` is enforced.
75+
76+
```python
77+
import pytest
78+
from typing import Literal
79+
from pydantic import BaseModel, ValidationError
80+
from typeid.integrations.pydantic import TypeIDField
81+
82+
class Order(BaseModel):
83+
id: TypeIDField[Literal["order"]]
84+
85+
with pytest.raises(ValidationError):
86+
Order(id="user_01ke82dtesfn9bjcrzyzz54ya9")
87+
```
88+
89+
This fails with a validation error because the prefix does not match.
90+
91+
This is useful when you want the model itself to encode domain meaning
92+
(e.g. *this field must be a user ID, not just any ID*).
93+
94+
## Serialization
95+
96+
When exporting a model, TypeIDs are always serialized as strings.
97+
98+
```python
99+
from typing import Literal
100+
from pydantic import BaseModel
101+
from typeid.integrations.pydantic import TypeIDField
102+
103+
class User(BaseModel):
104+
id: TypeIDField[Literal["user"]]
105+
106+
u = User(id="user_01ke82dtesfn9bjcrzyzz54ya9")
107+
data = u.model_dump(mode="json")
108+
109+
assert data == {"id": "user_01ke82dtesfn9bjcrzyzz54ya9"}
110+
```
111+
112+
```python
113+
from typing import Literal
114+
from pydantic import BaseModel
115+
from typeid.integrations.pydantic import TypeIDField
116+
117+
class User(BaseModel):
118+
id: TypeIDField[Literal["user"]]
119+
120+
u = User(id="user_01ke82dtesfn9bjcrzyzz54ya9")
121+
json_data = u.model_dump_json()
122+
123+
assert json_data == '{"id":"user_01ke82dtesfn9bjcrzyzz54ya9"}'
124+
```
125+
126+
This keeps JSON output simple and predictable.
127+
128+
## JSON Schema / OpenAPI
129+
130+
The generated schema looks roughly like this:
131+
132+
```yaml
133+
id:
134+
type: string
135+
format: typeid
136+
description: TypeID with prefix 'user'
137+
examples:
138+
- user_01ke82dtesfn9bjcrzyzz54ya9
139+
```
140+
141+
Notes:
142+
143+
* The schema does not hard-code internal regex details.
144+
* Actual validation is handled by the TypeID core.
145+
* The schema is meant to document intent, not re-implement parsing rules.
146+
147+
## Why `Literal["user"]`?
148+
149+
The recommended form is:
150+
151+
```text
152+
TypeIDField[Literal["user"]]
153+
```
154+
155+
This works cleanly with:
156+
157+
* Ruff
158+
* Pyright / MyPy
159+
* IDE type checkers
160+
161+
Using `Literal` makes the prefix a real compile-time constant and avoids
162+
annotation edge cases.
163+
164+
## FastAPI
165+
166+
FastAPI uses Pydantic v2, so no extra integration is needed.
167+
168+
TypeID fields work automatically in request and response models,
169+
including OpenAPI output, as soon as you use them in a Pydantic model.
170+
171+
## Design notes
172+
173+
* The TypeID core does not import Pydantic.
174+
* All framework-specific code lives in `typeid.integrations.pydantic`.
175+
* Parsing and validation rules live in the core, not in the adapter.
176+
177+
This keeps the integration small and easy to maintain.
178+
179+
*That’s it — no magic, no hidden behavior.*

docs/reference/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# CLI
22

3-
::: typeid.cli
3+
::: typeid.cli.main

docs/reference/factory.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Factory
22

3-
::: typeid.factory
3+
::: typeid.core.factory
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Pydantic V2 Integration
2+
3+
::: typeid.integrations.pydantic.v2

docs/reference/typeid.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# TypeID
22

3-
::: typeid.typeid.TypeID
3+
::: typeid.TypeID

0 commit comments

Comments
 (0)