Skip to content

Setup

Installation

pip install cadwyn

Project structure

The recommended directory structure for cadwyn is as follows:

├── data    # Any name or structure could be used here
│   ├── __init__.py
│   └── head    # This is the `head_schemas_package` and it must be named `head`
│       ├── __init__.py
│       └── users.py
└── versions
    ├── __init__.py     # Your version bundle goes here
    └── v2001_01_01.py  # Your version changes go here for each new version

Here is an initial API setup where the User has a single address. We will be implementing two routes - one for creating a user and another for retrieving user details. We'll be using "int" for ID for simplicity. Please note that we will use a dict in place of a database for simplicity of our examples but do not ever do it in real life.

The first API you come up with usually doesn't require more than one address -- why bother?

So we create our file with schemas:

# data/head/users.py
from pydantic import BaseModel
import uuid


class BaseUser(BaseModel):
    address: str


class UserCreateRequest(BaseUser):
    pass


class UserResource(BaseUser):
    id: uuid.UUID

Then we create our version bundle which will keep track of our API versions:

# versions/__init__.py
from cadwyn.structure import Version, VersionBundle, HeadVersion
from datetime import date
from data import head


version_bundle = VersionBundle(
    HeadVersion(),
    Version(date(2001, 1, 1)),
    head_schemas_package=head,
)

Generating versioned schemas

Now let's generate the only version of our schemas -- the one we created in the first step:

cadwyn codegen versions:version_bundle

WARNING Cadwyn doesn't edit your imports when generating schemas so if you make any imports from versioned code to versioned code, I would suggest using relative imports to make sure that they will still work as expected after code generation.

Generating versioned routes

# routes.py
from data.head.users import UserCreateRequest, UserResource
from versions import version_bundle
from cadwyn import VersionedAPIRouter, Cadwyn
import uuid
import uvicorn

database_parody = {}
router = VersionedAPIRouter()


@router.post("/users", response_model=UserResource)
async def create_user(payload: UserCreateRequest):
    id_ = uuid.uuid4()
    database_parody[id_] = {
        "id": id_,
        "address": payload.address,
    }
    return database_parody[id_]


@router.get("/users/{user_id}", response_model=UserResource)
async def get_user(user_id: uuid.UUID):
    return database_parody[user_id]


app = Cadwyn(versions=version_bundle)
app.generate_and_include_versioned_routers(router)

uvicorn.run(app)

That's it! Our app is ready to run.

Cadwyn has just generated a separate directory with the versioned schemas for us: one for each API version defined in our VersionBundle. If we run the app, we will see the following dashboard:

Dashboard with one version