cot

repository·master·Indexed 21 days ago

https://github.com/cot-rs/cot

A modern, fast, and batteries-included web framework for Rust built on top of axum. Designed for intuitive development with a Django-inspired API, cot features an integrated ORM, a built-in admin panel, and strong type safety across views, templates, and database interactions. It includes the cot-cli tool for project scaffolding and automated database migration management.

Tokens
57.9K
Snippets
213
Records
245
Agent score
77%

What's inside cot

  1. Overview of Cot features

    master

    Cot is a batteries-included web framework for Rust built on top of axum. Key features include:

    • Django-inspired API: Designed for intuitive and rapid development with sensible defaults.
    • Integrated ORM: Uses Rust types as the source of truth for database interactions and automatic migration generation.
    • Type Safety: Leverages Rust's type system across views, the ORM, the admin panel, and templates to catch errors early.
    • Built-in Admin Panel: Provides an out-of-the-box interface for managing application data, which is easily customizable.
    • Secure by Default: Implements protections against common modern web vulnerabilities automatically.
  2. Compare Cot with other Rust web frameworks

    master

    Cot is a batteries-included, opinionated web framework inspired by Django. It is designed for developer velocity by providing integrated tools that other modular frameworks require you to assemble manually.

    Key Differentiators

    • Admin Panel: Cot includes a built-in admin interface; most other frameworks (Axum, Actix-web, Rocket, Loco) do not.
    • Migrations: Cot features auto-generated migrations derived directly from your Rust structs.
    • ORM: Cot uses an integrated ORM (Cot ORM, based on SeaORM), whereas modular frameworks are agnostic.
    • Underlying Engine: Cot is built on top of Axum.

    Decision Matrix

    FeatureCotAxumActix-webRocketLoco
    PhilosophyBatteries-includedModularModularBatteries-includedBatteries-included
    EngineAxumHyper/TokioActixHyper/TokioAxum
    ORMIntegratedAgnosticAgnosticAgnosticSeaORM
    Admin PanelBuilt-inNoNoNoNo
    MigrationsAuto-generatedExternalExternalExternalExternal/CLI
    TemplatingAskama (built-in)AgnosticAgnosticAgnosticAgnostic
  3. Define and use Foreign Key relationships

    master

    Relationships between models are defined using the ForeignKey<T> type. Cot automatically creates the database-level foreign key constraint.

    Note on fetching: Cot does not automatically fetch related models (lazy loading). To access the related model, you must explicitly call .get(db) on the ForeignKey field.

    Example definition and usage:

    use cot::db::ForeignKey;
    
    #[model]
    pub struct Link {
        #[model(primary_key)]
        id: Auto<i64>,
        user: ForeignKey<User>,
    }
    
    #[model]
    pub struct User {
        #[model(primary_key)]
        id: Auto<i64>,
        name: String,
    }
    
    // Usage to fetch the related user:
    // let user = link.user.get(db).await?;
    use cot::db::ForeignKey;
    
    #[model]
    pub struct Link {
        #[model(primary_key)]
        id: Auto<i64>,
        user: ForeignKey<User>,
    }
    
    #[model]
    pub struct User {
        #[model(primary_key)]
        id: Auto<i64>,
        name: String,
    }
  4. When to choose Cot vs. Axum

    master

    Cot is built on top of Axum, meaning you get the performance and Tower ecosystem compatibility of Axum with additional high-level abstractions.

    • Choose Axum if: You need a minimalist microservice, want full control over every component in your stack, or do not require a database or UI management.
    • Choose Cot if: You want a full-stack experience with standard conventions. Cot manages the 'glue code' for authentication, sessions, and databases, allowing you to focus on business logic.
  5. Isolate cache namespaces using prefixes

    master

    To prevent data collisions between different environments (e.g., production vs. development) or different versions of the same application, use the prefix configuration.

    When a prefix is set, all keys are automatically formatted as {prefix}:{key}. This ensures each instance operates in its own isolated namespace.

    [cache]
    prefix = "v1"
  6. When to choose Cot vs. Actix-web

    master

    Actix-web is optimized for extreme performance and the Actor model.

    • Choose Actix-web if: Raw request-per-second performance is your absolute priority.
    • Choose Cot if: You prioritize developer velocity. Cot provides high-level tools like an Admin panel and auto-migrations to speed up development, while still maintaining high performance via its Axum foundation.
  7. Understand the App and Project abstractions

    master

    Cot organizes code into two main hierarchical abstractions:

    App

    An App is a collection of views and components (like migrations and static files) that typically represents a logical part of your service (e.g., an admin panel or an API). An App must implement the App trait, which includes methods for:

    • name(): A unique identifier used for database tables and URL reversing.
    • router(): Defines the routes for the app.
    • migrations(): Provides a list of database migrations.
    • static_files(): Defines which static files the app serves.

    Project

    A Project is the top-level container that ties everything together. It is the entry point of your application. A Project implements the Project trait and is responsible for:

    • cli_metadata(): Providing metadata for the Cot CLI.
    • register_apps(): Registering all App instances used by the service.
    • middlewares(): Defining the middleware stack applied to all routes (e.g., StaticFilesMiddleware, LiveReloadMiddleware).

    The application starts by returning the Project implementation in the #[cot::main] function.

    #[cot::main]
    fn main() -> impl Project {
        CotTutorialProject
    }
  8. When to choose Cot vs. Loco

    master

    Loco is often described as 'Rails for Rust'.

    • Choose Loco if: You prefer the Ruby on Rails philosophy and project structure.
    • Choose Cot if: You prefer the Django philosophy. Cot is specifically designed to map Rust structs to database tables and provide an auto-generated Admin panel, making it ideal for quickly launching applications with standard web features.
  9. When to choose Cot vs. Rocket

    master

    Rocket focuses on developer ergonomics through heavy use of macros.

    • Choose Rocket if: You prefer Rocket's specific macro-based API style and want to pick your own independent database layer.
    • Choose Cot if: You want a 'Django-like' experience where standard features like user management, permissions, and admin interfaces are provided out of the box.
  10. Handle custom types and HTML escaping

    master

    Custom Types

    To render a custom Rust type in a template, implement the std::fmt::Display trait for it.

    HTML Escaping

    Askama escapes all output by default to prevent XSS.

    • To bypass escaping: Implement the HtmlSafe marker trait for your type.
    • Recommended approach: Use cot::html::HtmlTag to build HTML elements. It automatically handles escaping for attributes and content.

    Example using HtmlTag:

    impl Display for Item {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            let mut tag = HtmlTag::input("text");
            tag.attr("value", &self.title); // Safely escaped
            write!(f, "{}", tag.render().as_str())
        }
    }
    use std::fmt::Display;
    use cot::Template;
    use cot::html::HtmlTag;
    
    struct Item { title: String }
    
    impl Display for Item {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            let mut tag = HtmlTag::input("text");
            tag.attr("value", &self.title); 
            write!(f, "{}", tag.render().as_str())
        }
    }
  11. How path and query parameters work in OpenAPI

    master

    Cot automatically detects and documents path parameters and URL query parameters if you use the appropriate extractors:

    • Path Parameters: Use cot::request::extractors::Path. The parameter name in the path (e.g., {user_id}) must match the extractor logic.
    • Query Parameters: Use cot::request::extractors::UrlQuery with a struct that implements JsonSchema.
    // Path Parameter Example
    use cot::request::extractors::Path;
    async fn get_user(Path(user_id): Path<i32>) -> cot::Result<Response> { /* ... */ }
    // Route: Route::with_api_handler("/users/{user_id}", api_get(get_user));
    
    // Query Parameter Example
    use cot::request::extractors::UrlQuery;
    #[derive(Deserialize, JsonSchema)]
    struct UserQuery {
        active: Option<bool>,
        role: Option<String>,
    }
    async fn list_users(UrlQuery(query): UrlQuery<UserQuery>) -> cot::Result<Response> { /* ... */ }
    // Route: Route::with_api_handler("/users", api_get(list_users));
  12. Understand Cot guide snippet test types

    master

    The documentation test runner identifies snippets by their language and optional configuration tags. The following test types are supported:

    • rust: Snippets are wrapped in an async block inside a main function. Common symbols from cot and std are automatically imported. You can hide lines from the rendered guide by prefixing them with # .
    • rust,has_main: For snippets that define their own main function. No automatic imports are provided.
    • toml: Snippets are validated by parsing them as a Cot project configuration file.
    • html.j2: Snippets are compiled as Askama templates. The test environment includes dummy files (e.g., base.html, logo.png) to satisfy template references.