Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Cadwyn
https://github.com/zmievsa/cadwyn
Admin
Production-ready community-driven modern Stripe-like API versioning in FastAPI
Tokens:
16,725
Snippets:
51
Trust Score:
9.3
License:
MIT
Update:
1 year ago
Context
Chat
Benchmark
85
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Install Cadwyn Source: https://github.com/zmievsa/cadwyn/blob/main/docs/quickstart/setup.md Installs the Cadwyn library using pip. This is the initial step to start using Cadwyn for versioned FastAPI applications. ```bash pip install cadwyn ``` -------------------------------- ### Environment Setup with uv Source: https://github.com/zmievsa/cadwyn/blob/main/docs/home/CONTRIBUTING.md Steps to set up the development environment using uv for Python version management and dependency installation. This includes installing uv, syncing dependencies, and installing pre-commit hooks. ```shell uv sync ``` ```shell uv tool install pre-commit ``` ```shell pre-commit install --install-hooks ``` -------------------------------- ### Initial User API Setup Source: https://github.com/zmievsa/cadwyn/blob/main/docs/quickstart/tutorial.md Sets up a basic User API with a single address field and endpoints for creating and retrieving users. Uses a dictionary as a mock database. ```python from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class User(BaseModel): id: int name: str address: str users = {} @app.post("/users", response_model=User) def create_user(user: User): users[user.id] = user return user @app.get("/users/{user_id}", response_model=User) def get_user(user_id: int): return users[user_id] ``` -------------------------------- ### Serving Project Documentation Locally Source: https://github.com/zmievsa/cadwyn/blob/main/docs/home/CONTRIBUTING.md Command to serve the project's documentation locally using MkDocs. This allows developers to preview changes to the documentation before deploying them. ```shell mkdocs serve ``` -------------------------------- ### Running Tests Source: https://github.com/zmievsa/cadwyn/blob/main/docs/home/CONTRIBUTING.md Command to execute all tests within the Cadwyn project. This ensures that code changes do not introduce regressions and maintain code quality. ```shell make test ``` -------------------------------- ### Basic Versioned FastAPI App Source: https://github.com/zmievsa/cadwyn/blob/main/docs/quickstart/setup.md Creates a minimal versioned FastAPI application using Cadwyn. It demonstrates how to define API versions, which is a core feature distinguishing Cadwyn from standard FastAPI. ```python from fastapi import FastAPI from cadwyn import Cadwyn app = FastAPI() cadwyn = Cadwyn(app, api_versions=["2000-01-01"]) @app.get("/") def read_root(): return {"Hello": "World"} ``` -------------------------------- ### Running Type Checkers Source: https://github.com/zmievsa/cadwyn/blob/main/docs/home/CONTRIBUTING.md Command to run the Pyright type checker against the project. This enforces type safety and helps catch potential type-related errors before runtime. ```shell uv run pyright . ``` -------------------------------- ### Check Cadwyn CLI Version Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/cli.md Displays the installed version of the Cadwyn CLI. This command is useful for verifying the installation and ensuring you are using the correct version of the tool. It requires Cadwyn to be installed via pip. ```bash cadwyn --version ``` -------------------------------- ### Cadwyn App Setup with Versioned Routers Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/main_app.md Demonstrates the standard usage of Cadwyn by creating a `Cadwyn` application instance, defining versioned API routes using `VersionedAPIRouter`, and including these routers in the main app. It highlights how `generate_and_include_versioned_routers` automatically handles version generation. ```python from cadwyn import VersionedAPIRouter, Cadwyn from versions import my_version_bundle router = VersionedAPIRouter(prefix="/users") @router.get("/users/", tags=["users"]) async def read_users(): return [{"username": "Rick"}, {"username": "Morty"}] @router.get("/users/{username}", tags=["users"]) async def read_user(username: str): return {"username": username} app = Cadwyn(versions=my_version_bundle) app.generate_and_include_versioned_routers(router) ``` -------------------------------- ### Version Bundle Configuration Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/add_field.md Illustrates how to configure a version bundle by including the `HeadVersion` and specific `Version` objects with their associated `VersionChange` classes. This setup ensures proper schema versioning and migration handling. ```python from cadwyn import Version, VersionBundle, HeadVersion from datetime import date from .v2001_01_01 import MakeUserCountryRequired version_bundle = VersionBundle( HeadVersion(), Version("2001-01-01", MakeUserCountryRequired), Version("2000-01-01"), ) ``` -------------------------------- ### Version Bundle Configuration (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/add_field.md This Python snippet demonstrates how to configure a `VersionBundle` using the Cadwyn library. It defines the order and content of API versions, including the `HeadVersion` and specific dated versions, associating them with their respective `VersionChange` instructions. This setup is crucial for managing the API's versioning lifecycle. ```Python from cadwyn import Version, VersionBundle, HeadVersion from datetime import date from .v2001_01_01 import MakePhoneNonNullableInLatest, AddPhoneToUser version_bundle = VersionBundle( HeadVersion(MakePhoneNonNullableInLatest), Version("2001-01-01", AddPhoneToUser), Version("2000-01-01"), ) ``` -------------------------------- ### Hiding Version Changes and Instructions with Cadwyn Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/changelogs.md Demonstrates how to use the `cadwyn.hidden` function to mark specific version changes or instructions as private or internal, preventing them from being publicly visible in the generated changelog. This includes examples for hiding changes to endpoint paths and schema fields. ```python from cadwyn import hidden, VersionChange, endpoint from cadwyn.schema import schema class VersionChangeWithOneHiddenInstruction(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( hidden(endpoint("/users/{user_id}", ["GET"]).had(path="/users/{uid}")), ) @hidden class CompletelyHiddenVersionChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(User).field("address").existed_as(type=str), ) ``` -------------------------------- ### Define Schema with Integer ID Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/change_schema_without_endpoint.md This Python code defines a simple `User` schema with an `id` field initially typed as an integer. This serves as the starting point for schema modification. ```python from typing import Any class User: id: int name: str ``` -------------------------------- ### Cadwyn: Implement Response and Request Version Migration Source: https://github.com/zmievsa/cadwyn/blob/main/docs/quickstart/tutorial.md This Python code demonstrates how to implement version changes in Cadwyn to revert breaking changes. It shows how to migrate response models by converting a list of addresses back to a single address for older versions, and how to handle request migrations to keep business logic consistent across API versions. ```python from cadwyn.versions import VersionChange class UserResourceAddressMigration(VersionChange): """Migrates UserResource address field from list to single item.""" @property def version(self) -> str: return "2000-01-01" def migrate_response(self, response: dict) -> dict: """Converts the list of addresses back to a single address.""" if "addresses" in response and isinstance(response["addresses"], list) and response["addresses"]: response["address"] = response["addresses"].pop(0) if not response["addresses"]: del response["addresses"] return response def migrate_request(self, request: dict) -> dict: """Converts a single address back to a list for older versions.""" if "address" in request and "addresses" not in request: request["addresses"] = [request.pop("address")] return request ``` -------------------------------- ### Initialize Cadwyn with Default Header Versioning Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/api_version_parameter.md Demonstrates initializing Cadwyn with default settings for API versioning via a custom header. Specifies the header name and a single API version. ```python from cadwyn import Cadwyn, Version, VersionBundle app = Cadwyn( api_version_location="custom_header", api_version_parameter_name="X-API-VERSION", versions=VersionBundle(Version("2022-01-02")), ) ``` -------------------------------- ### Configure Cadwyn with Version Parameter Title and Description Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/api_version_parameter.md Shows how to provide a custom title and description for the API version parameter. These are passed to the underlying FastAPI Path or Header constructors, enhancing documentation. ```python app = Cadwyn( ..., api_version_title="My Great API version parameter", api_version_description="Description of my great API version parameter", ) ``` -------------------------------- ### User API with Breaking Change (Address List) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/quickstart/tutorial.md Modifies the User API to change the 'address' field from a string to a list of strings, introducing a breaking change for existing clients. ```python from fastapi import FastAPI from pydantic import BaseModel from typing import List app = FastAPI() class User(BaseModel): id: int name: str address: List[str] # Changed from str to List[str] users = {} @app.post("/users", response_model=User) def create_user(user: User): users[user.id] = user return user @app.get("/users/{user_id}", response_model=User) def get_user(user_id: int): return users[user_id] ``` -------------------------------- ### Configure Cadwyn with Path Parameter Versioning Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/api_version_parameter.md Illustrates configuring Cadwyn to use a URL path parameter for API versioning, specifying the parameter name. This method integrates versioning directly into the URL structure. ```python from cadwyn import Cadwyn, Version, VersionBundle app = Cadwyn( api_version_location="path", api_version_parameter_name="api_version", versions=VersionBundle(Version("2022-01-02")), ) ``` -------------------------------- ### Render Single Model Schema with Cadwyn CLI Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_generation.md This command renders a specific schema (like a Pydantic model or enum) from a module to stdout for a particular version. It helps in examining the structure of individual schemas and understanding how they change across versions, serving as a close approximation for manual review. ```bash cadwyn render model data.schemas:UserCreateRequest --app=main:app --version=2024-05-26 ``` -------------------------------- ### Render Module Schemas with Cadwyn CLI Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_generation.md This command renders all schemas within a specified module to stdout, providing a human-readable approximation of their structure for a given version. It's useful for inspecting schema evolution but may not be suitable for full code generation due to limitations like not handling schema renamings in class bases. ```bash cadwyn render module data.schemas --app=main:app --version=2024-05-26 ``` -------------------------------- ### Configure Cadwyn with Arbitrary String Versions Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/api_version_parameter.md Configures Cadwyn to accept arbitrary strings as API versions. This offers flexibility, allowing versions like 'v1', 'v2', or custom identifiers, with order determined by their declaration. ```python from cadwyn import Cadwyn, Version, VersionBundle app = Cadwyn( api_version_format="string", versions=VersionBundle( Version("v2"), Version("anything_can_be_a_version"), Version("v1"), ), ) ``` -------------------------------- ### Define Migration for Deleted Endpoint Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/endpoint_migrations.md Shows how to define a `VersionChange` instruction to explicitly mark an endpoint as existing in older versions. This implicitly signifies that the endpoint is deleted or removed in newer versions. ```python from cadwyn import VersionChange, endpoint class MyChange(VersionChange): description = "Marks /users/{user_id} as deleted in newer versions." instructions_to_migrate_to_previous_version = ( endpoint("/users/{user_id}", ["GET"]).existed, ) ``` -------------------------------- ### Configure Cadwyn with Date Format Versions Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/api_version_parameter.md Sets Cadwyn to expect API versions in ISO date format. This ensures that only valid dates are accepted as version identifiers, promoting structured versioning. ```python from cadwyn import Cadwyn, Version, VersionBundle app = Cadwyn( api_version_format="date", versions=VersionBundle(Version("2022-01-02")), ) ``` -------------------------------- ### Add Enum Members in Python Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/enum_migrations.md Demonstrates how to use Cadwyn's `enum` instruction to specify added members to an enum. This is crucial for versioning as adding enum members can be a breaking change for clients. ```python from cadwyn import VersionChange, enum from enum import auto class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( enum(my_enum).had(foo="baz", bar=auto()), ) ``` -------------------------------- ### Handle Duplicate Endpoints with Specific Function Names Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/endpoint_migrations.md Provides a method to resolve conflicts when multiple endpoint functions share the same path and HTTP method. By specifying the `func_name` in the `endpoint` instruction, Cadwyn can differentiate and manage these duplicates, marking one as `existed` and another as `didnt_exist` to resolve the conflict. ```python from fastapi.params import Param from fastapi.headers import Header from typing import Annotated from cadwyn import VersionedAPIRouter, VersionChange, endpoint router = VersionedAPIRouter() @router.only_exists_in_older_versions @router.get("/users") def get_users_by_name_before_we_started_using_params( user_name: Annotated[str, Header()] ): """Do some logic with user_name""" @router.get("/users") def get_users_by_name(user_name: Annotated[str, Param()]): """Do some logic with user_name""" class UseParamsInsteadOfHeadersForUserNameFiltering(VersionChange): description = ( "Use params instead of headers for user name filtering in GET /users " "because using headers is a bad API practice in such scenarios." ) instructions_to_migrate_to_previous_version = ( # Specify func_name to distinguish identical path/method endpoints endpoint( "/users", ["GET"], func_name="get_users_by_name_before_we_started_using_params", ).existed, endpoint("/users", ["GET"], func_name="get_users_by_name").didnt_exist, ) ``` -------------------------------- ### Configure Cadwyn with Custom Header Name Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/api_version_parameter.md Shows how to set a custom header name for API version detection in Cadwyn, overriding the default 'X-API-VERSION'. This allows for flexible header naming conventions. ```python from cadwyn import Cadwyn, Version, VersionBundle app = Cadwyn( api_version_location="custom_header", api_version_parameter_name="MY-GREAT-HEADER", versions=VersionBundle(Version("2022-01-02")), ) ``` -------------------------------- ### Define Migration for Non-Existing Endpoint in Old Versions Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/endpoint_migrations.md Illustrates how to mark an endpoint as not existing in older API versions. This is done within a `VersionChange` instruction using `endpoint(...).didnt_exist`. This approach is generally not recommended for adding new endpoints. ```python from cadwyn import VersionChange, endpoint class MyChange(VersionChange): description = "Marks /companies/{company_id} as non-existing in older versions." instructions_to_migrate_to_previous_version = ( endpoint("/companies/{company_id}", ["GET"]).didnt_exist, ) ``` -------------------------------- ### Cadwyn Schema DSL for Field Migration Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/add_field.md This APIDOC entry illustrates the usage of Cadwyn's Schema DSL for defining migration instructions. It shows how to target a specific field within a schema, define its expected type, and specify default values or constraints. This DSL is used within `VersionChange` classes to declare how schemas should be transformed between versions. ```APIDOC schema(UserCreateRequest).field("phone").had(type=str) - Description: Specifies that the 'phone' field in UserCreateRequest should have a type of 'str'. - Usage: Used to enforce a non-nullable string type. schema(UserCreateRequest).field("phone").didnt_have("default") - Description: Specifies that the 'phone' field in UserCreateRequest should not have a default value. - Usage: Used to ensure a field is explicitly provided. schema(UserCreateRequest).field("phone").had(type=str | None, default=None) - Description: Specifies that the 'phone' field in UserCreateRequest should be nullable (type str or None) and have a default value of None. - Usage: Used to allow optional phone numbers or support older versions lacking the field. ``` -------------------------------- ### Add Nullable Phone Field Migration (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/add_field.md This Python snippet defines a `VersionChange` class for schema migration, specifically adding a 'phone' field to `UserCreateRequest`. It sets the field to be nullable with a default value of `None` to accommodate older API versions that did not have this field. This ensures compatibility when migrating requests from older versions to the HEAD version. ```Python class AddPhoneToUser(VersionChange): description = ( "Add a required phone field to User to allow us to do 2fa and to " "make it possible to verify new user accounts using an sms." ) instructions_to_migrate_to_previous_version = ( schema(UserCreateRequest) .field("phone") .had(type=str | None, default=None), ) ``` -------------------------------- ### Define Phone Non-Nullable Migration (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/add_field.md This Python snippet defines a `VersionChange` class to manage schema evolution for a 'phone' field. It specifies instructions to ensure the 'phone' field is non-nullable in the HEAD version, supporting older API versions where it might have been nullable. It utilizes Cadwyn's schema DSL to define the field's type and default behavior. ```Python from cadwyn import VersionChange, schema from users import UserCreateRequest class MakePhoneNonNullableInLatest(VersionChange): description = ( "Make sure the phone is nullable in the HEAD version to support " "versions older than 2001_01_01 where it became non-nullable" ) instructions_to_migrate_to_previous_version = ( schema(UserCreateRequest).field("phone").had(type=str), schema(UserCreateRequest).field("phone").didnt_have("default"), ) ``` -------------------------------- ### Generate Versioned Schemas without FastAPI Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_generation.md Demonstrates how to programmatically generate versioned models using Cadwyn outside of a FastAPI application context. This involves using `generate_versioned_models` with a version bundle to create schema classes for specific versions. ```python import cadwyn from my_versions import version_bundle, MyVersionedSchema schema_generators = generate_versioned_models(version_bundle) MyVersionedSchemaFrom2025 = schema_generators["2025-11-16"][MyVersionedSchema] ``` -------------------------------- ### Add RemoveZodiacSign Migration to Version Bundle (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/remove_field.md This Python snippet shows how to integrate the custom migration class into the version bundle. It defines the versioning structure, including the new migration for the '2001-01-01' version. ```python # versions/__init__.py from cadwyn import Version, VersionBundle, HeadVersion from datetime import date from .v2001_01_01 import RemoveZodiacSignFromUser version_bundle = VersionBundle( HeadVersion(), Version("2001-01-01", RemoveZodiacSignFromUser), Version("2000-01-01"), ) ``` -------------------------------- ### Rename Schema in Older Version (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_migrations.md Demonstrates how to rename a schema in an older version using Cadwyn. This ensures that the schema's name is updated in the generated OpenAPI specification, replacing all references to the original name with the new one. ```python from cadwyn import VersionChange, schema class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema).had(name="OtherSchema"), ) ``` -------------------------------- ### Mark Endpoint as Deleted in New Versions Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/endpoint_migrations.md Demonstrates how to mark an endpoint for deletion in newer API versions. This is achieved by using the `@router.only_exists_in_older_versions` decorator on the endpoint function and then specifying its existence in older versions via a migration instruction. ```python from fastapi.routing import APIRouter router = APIRouter() @router.only_exists_in_older_versions @router.get("/users/{user_id}") async def my_old_endpoint(): ... # Endpoint logic ``` -------------------------------- ### Change Endpoint Attributes Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/endpoint_migrations.md Explains how to modify specific attributes of an endpoint for older versions, such as its description. This is achieved using the `.had()` method on an `endpoint` instruction. Migrations are only necessary for breaking changes. ```python from cadwyn import VersionChange, endpoint class MyChange(VersionChange): description = "Updates description for /users/{user_id} in older versions." instructions_to_migrate_to_previous_version = ( endpoint("/users/{user_id}", ["GET"]).had( description="My old description" ), ) ``` -------------------------------- ### Add Field to Older Schema (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_migrations.md Demonstrates how to add a field to an older schema version using Cadwyn's `VersionChange`. This involves specifying the schema, the field name, its type, and any associated Pydantic `Field` information. ```python from pydantic import Field from cadwyn import VersionChange, schema class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema) .field("foo") .existed_as(type=list[str], info=Field(description="Foo")), ) ``` -------------------------------- ### Remove Field from Older Schema (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_migrations.md Illustrates how to mark a field as non-existent in an older schema version using Cadwyn. This is achieved by referencing the schema and field, and asserting that it `didnt_exist`. ```python from cadwyn import VersionChange, schema class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema).field("foo").didnt_exist, ) ``` -------------------------------- ### Add Multiple Migrations to Version Bundle (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/remove_field.md This Python code updates the version bundle to include multiple migrations, including one for removing a field from the latest version and another for maintaining support in older versions. It demonstrates how to manage complex schema evolution within the versioning system. ```python # versions/__init__.py from cadwyn import Version, VersionBundle, HeadVersion from datetime import date from .v2001_01_01 import RemoveZodiacSignFromUser, RemoveMiddleNameFromLatestVersion, RemoveMiddleNameFromUser version_bundle = VersionBundle( HeadVersion(RemoveMiddleNameFromLatestVersion), Version("2001-01-01", RemoveMiddleNameFromUser), Version("2000-01-01"), ) ``` -------------------------------- ### Modify Field Attributes in Older Schema (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_migrations.md Shows how to modify existing field attributes, such as setting a description, or conversely, removing specific attributes like a description from a field in an older schema version using Cadwyn. ```python from cadwyn import VersionChange, schema class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema).field("foo").had(description="Foo"), ) ``` ```python from cadwyn import VersionChange, schema class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema).field("foo").didnt_have("description"), ) ``` -------------------------------- ### Make User Country Required Migration Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/add_field.md Demonstrates how to make a field required in a request schema while providing a compatible default value in older versions. This involves defining a `VersionChange` class with instructions for migrating to previous versions and implementing a request conversion method. ```python from cadwyn import \ VersionChange, \ schema, \ convert_request_to_next_version_for from users import UserCreateRequest, UserResource class MakeUserCountryRequired(VersionChange): description = 'Make user country required instead of the "USA" default' instructions_to_migrate_to_previous_version = ( schema(UserCreateRequest).field("country").had(default="USA"), ) @convert_request_to_next_version_for(UserCreateRequest) def add_default_value_to_country_field_in_request(request: RequestInfo): request.body["country"] = request.body.get("country", "USA") ``` -------------------------------- ### Python Default for Optional Fields Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/remove_field.md Illustrates making a field optional in Python by setting its default value to `None`. This is a straightforward method for fields that do not require a specific default value when absent. ```python # Example of making a field optional with a default value of None # Assuming a class or data structure context # field_name: Optional[Any] = None ``` -------------------------------- ### Add Validator to Older Schema (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_migrations.md Explains how to add a custom validator to an older schema version with Cadwyn. This involves defining a validator function (e.g., using `@field_validator`) and then referencing it within the `VersionChange` instructions. ```python from pydantic import Field, field_validator from cadwyn import VersionChange, schema @field_validator("foo") def validate_foo(cls, value): if not ":" in value: raise TypeError return value class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema).validator(validate_foo).existed, ) ``` -------------------------------- ### Python Default Factory for Optional Fields Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/remove_field.md Demonstrates how to make a field optional in Python using `default_factory` for dynamic defaults like current timestamps. This approach is suitable for fields where a sensible default can be generated at runtime. ```python from datetime import datetime # Example of making a field optional with a default factory # Assuming a class or data structure context # field_name: Optional[datetime] = field(default_factory=datetime.now) ``` -------------------------------- ### Cadwyn: Rename Summary to Bio in User Schema Migration Source: https://github.com/zmievsa/cadwyn/blob/main/docs/how_to/change_openapi_schemas/rename_a_field_in_schema.md This Python code demonstrates a Cadwyn `VersionChange` to rename the 'summary' field to 'bio' in user schemas. It includes schema conversion instructions and methods to adapt request and response bodies for version compatibility. ```python from cadwyn import ( VersionChange, schema, convert_response_to_previous_version_for, convert_request_to_next_version_for, ResponseInfo, RequestInfo, ) from users import BaseUser, UserCreateRequest, UserResource class RenameSummaryIntoBioInUser(VersionChange): description = ( "Rename 'summary' field into 'bio' to keep up with industry standards" ) instructions_to_migrate_to_previous_version = ( schema(BaseUser).field("bio").had(name="summary"), ) @convert_request_to_next_version_for(UserCreateRequest) def rename_bio_to_summary(request: RequestInfo): request.body["summary"] = request.body.pop("bio") @convert_response_to_previous_version_for(UserResource) def rename_bio_to_summary(response: ResponseInfo): response.body["bio"] = response.body.pop("summary") ``` -------------------------------- ### Remove Enum Members in Python Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/enum_migrations.md Illustrates how to use Cadwyn's `enum` instruction to declare removed members from an enum. Removing enum members is also a breaking change that requires careful version management. ```python from cadwyn import VersionChange, enum class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( enum(my_enum).didnt_have("foo", "bar"), ) ``` -------------------------------- ### Remove Validator from Older Schema (Python) Source: https://github.com/zmievsa/cadwyn/blob/main/docs/concepts/schema_migrations.md Details how to remove a validator from an older schema version using Cadwyn. This is done by referencing the schema and the specific validator method that needs to be removed, marking it as `didnt_exist`. ```python from pydantic import Field, validator from cadwyn import VersionChange, schema class MyChange(VersionChange): description = "..." instructions_to_migrate_to_previous_version = ( schema(MySchema).validator(MySchema.validate_foo).didnt_exist, ) ```