Skip to content

feat: add CommonMiddleware - #639

Open
ZhangStudyLife wants to merge 1 commit into
cot-rs:masterfrom
ZhangStudyLife:feat/common-middleware-637
Open

feat: add CommonMiddleware#639
ZhangStudyLife wants to merge 1 commit into
cot-rs:masterfrom
ZhangStudyLife:feat/common-middleware-637

Conversation

@ZhangStudyLife

@ZhangStudyLife ZhangStudyLife commented Aug 9, 2026

Copy link
Copy Markdown

Related issue or discussion

Fixes #637.

Description

Adds CommonMiddleware to consolidate the five middlewares enabled by the generated project template while preserving their existing layer order. Each child middleware can be enabled or disabled under [middlewares]; defaults preserve the current generated-project behavior.

The project template and introduction now use CommonMiddleware, and configuration plus trailing-slash behavior have regression coverage.

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Refactor / cleanup
  • Performance improvement
  • Other (describe above)

Checklist

  • I've read the contributing guide
  • Tests pass locally (just test-all)
  • Code passes clippy (just clippy)
  • Code is properly formatted (cargo fmt)
  • New tests added (regression test for bugs, coverage for new features)
  • Documentation (both code and site) updated (if applicable)

Additional validation: MSRV 1.94, --no-default-features, and 154 external-dependency tests with the repository Docker Compose services.

Copilot AI lite review requested due to automatic review settings August 9, 2026 01:47
@github-actions github-actions Bot added A-docs Area: Documentation C-cli Crate: cot-cli (issues and Pull Requests related to Cot CLI) C-lib Crate: cot (main library crate) labels Aug 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new CommonMiddleware layer to bundle the default middleware stack used by generated Cot projects, while keeping the same middleware ordering and making each child middleware individually configurable via [middlewares]. This reduces boilerplate in templates/docs and introduces regression coverage for config-driven behavior (notably trailing-slash handling).

Changes:

  • Introduce CommonMiddleware in cot to compose trailing-slash, live-reload, session, auth, and static-files middleware with per-middleware enable flags.
  • Extend configuration to support auth, static_files, and trailing_slash enable toggles (and add enabled to session config), with defaults preserving existing generated-project behavior.
  • Update the project template and documentation to use CommonMiddleware, and add tests validating config-driven behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
docs/introduction.md Updates the guide example to use CommonMiddleware and explains per-child runtime configurability.
cot/src/middleware.rs Implements CommonMiddleware and adds a regression test ensuring it respects trailing-slash enablement.
cot/src/config.rs Adds EnabledMiddlewareConfig, extends MiddlewareConfig with new enable toggles, and updates config parsing tests.
cot-cli/src/project_template/src/main.rs Simplifies generated project boilerplate by replacing individual middleware wiring with CommonMiddleware.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.23810% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cot/src/middleware.rs 93.58% 3 Missing and 2 partials ⚠️
Flag Coverage Δ
rust 90.25% <95.23%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cot/src/config.rs 94.77% <100.00%> (+0.18%) ⬆️
cot/src/middleware.rs 93.46% <93.58%> (+0.02%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ElijahAhianyo ElijahAhianyo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution! Please address the comments and then we can merge this. Also, please feel free to ask questions on anything you need clarity on.

Comment thread cot/src/middleware.rs
type ConfiguredLiveReloadMiddleware = LiveReloadMiddleware;
#[cfg(not(feature = "live-reload"))]
type ConfiguredLiveReloadMiddleware = tower::layer::util::Identity;
type CommonMiddlewareLayer = (

@ElijahAhianyo ElijahAhianyo Aug 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not exactly sure if this is the right approach. I would expect the CommonMiddleware to be a stack of default middlewares that are enabled as a group by default without users manually registering them at startup time, not particularly one where some can be enabled and some disabled. That defeats the purpose of grouping them. If users want all default middlewares enabled, they should only have to register this middleware; however, they should be able to opt out and manually register ones they want.

A rough idea I had in mind was along the lines of:

use tower::Layer;

use crate::middleware::TrailingSlashMiddleware;
use crate::project::MiddlewareContext;

#[derive(Debug, Clone)]
pub struct CommonMiddleware {
    trailing_slash: TrailingSlashMiddleware,
}

impl CommonMiddleware {
    #[must_use]
    pub fn from_context(context: &MiddlewareContext) -> Self {
        Self {
            trailing_slash: TrailingSlashMiddleware::from_context(context),
        }
    }
}

impl<S> Layer<S> for CommonMiddleware {
    type Service = <TrailingSlashMiddleware as Layer<S>>::Service;

    fn layer(&self, inner: S) -> Self::Service {
        self.trailing_slash.layer(inner)
    }
}

If we decide to add the session and auth middlewares(as an example) to the common middlewares, then it will look something like this:

#[derive(Debug, Clone)]
pub struct CommonMiddleware {
    trailing_slash: TrailingSlashMiddleware,
    session: SessionMiddleware,
    auth: AuthMiddleware,
}

impl CommonMiddleware {
    #[must_use]
    pub fn from_context(context: &MiddlewareContext) -> Self {
        Self {
            trailing_slash: TrailingSlashMiddleware::from_context(context),
            session: SessionMiddleware::from_context(context),
            auth: AuthMiddleware::new(),
        }
    }
}

impl<S> Layer<S> for CommonMiddleware
where
    AuthMiddleware: Layer<S>,
    SessionMiddleware: Layer<<AuthMiddleware as Layer<S>>::Service>,
    TrailingSlashMiddleware:
    Layer<<SessionMiddleware as Layer<<AuthMiddleware as Layer<S>>::Service>>::Service>,
{
    type Service = <TrailingSlashMiddleware as Layer<
        <SessionMiddleware as Layer<<AuthMiddleware as Layer<S>>::Service>>::Service,
    >>::Service;

    fn layer(&self, inner: S) -> Self::Service {
        let service = self.auth.layer(inner);
        let service = self.session.layer(service);
        self.trailing_slash.layer(service)
    }
}

What I am not sure of is if we want to have the auth, session, and live middlewares as part of the common middlewares since they may not necessarily be the common denominator of every app. @m4tx Do you want to weigh in on which middlewares should be labelled as common?

One other thing to note, which I believe should be a separate issue(and not within the scope of this PR), is that registering the common middleware along with middlewares already present in the common middleware (or duplicating middlewares in general) could be wasteful.

handler
    .middleware(CommonMiddleware::from_context(context))
    .middleware(TrailingSlashMiddleware::from_context(context))

I believe this should be permitted; however, we should probably warn the user of this at runtime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-docs Area: Documentation C-cli Crate: cot-cli (issues and Pull Requests related to Cot CLI) C-lib Crate: cot (main library crate)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CommonMiddlware for enabled-by-default middlewares

3 participants