Skip to main content

Project

Trait Project 

Source
pub trait Project {
    // Provided methods
    fn cli_metadata(&self) -> CliMetadata { ... }
    fn config(&self, config_name: &str) -> Result<ProjectConfig> { ... }
    fn register_tasks(&self, cli: &mut Cli) { ... }
    fn register_apps(
        &self,
        apps: &mut AppBuilder,
        context: &RegisterAppsContext,
    ) { ... }
    fn auth_backend(&self, context: &AuthBackendContext) -> Arc<dyn AuthBackend> { ... }
    fn middlewares(
        &self,
        handler: RootHandlerBuilder,
        context: &MiddlewareContext,
    ) -> RootHandler { ... }
    fn error_handler(&self) -> DynErrorPageHandler { ... }
}
Expand description

The main trait for a Cot project.

This is the main entry point for your application. This trait defines the configuration, apps, and other project-wide resources.

It’s mainly meant to be used with the cot::main attribute macro.

§Examples

use cot::Project;
use cot::cli::CliMetadata;

struct MyProject;
impl Project for MyProject {
    fn cli_metadata(&self) -> CliMetadata {
        cot::cli::metadata!()
    }
}

#[cot::main]
fn main() -> impl Project {
    MyProject
}

Provided Methods§

Source

fn cli_metadata(&self) -> CliMetadata

Returns the metadata for the CLI.

This method is used to set the name, version, authors, and description of the CLI application. This is meant to be typically used with cli::metadata!() which automatically retrieves this data from the crate metadata.

The default implementation sets the name, version, authors, and description of the cot crate.

§Examples
use cot::Project;
use cot::cli::CliMetadata;

struct HelloProject;
impl Project for HelloProject {
    fn cli_metadata(&self) -> CliMetadata {
        cot::cli::metadata!()
    }
}
Source

fn config(&self, config_name: &str) -> Result<ProjectConfig>

Returns the configuration for the project.

The default implementation reads the configuration from the config directory in the current working directory (for instance, if config_name is test, then config/test.toml in the current working directory is read). If the file does not exist, it tries to read the file directly at config_name path.

You might want to override this method if you want to read the configuration from a different source, or if you want to hardcode it in the binary.

§Errors

This method may return an error if it cannot read or parse the configuration.

§Examples
use cot::Project;
use cot::config::ProjectConfig;

struct MyProject;
impl Project for MyProject {
    fn config(&self, config_name: &str) -> cot::Result<ProjectConfig> {
        Ok(ProjectConfig::default())
    }
}
Source

fn register_tasks(&self, cli: &mut Cli)

Adds a task to the CLI.

This method is used to add a task to the CLI. The task will be available as a subcommand of the main CLI command.

§Examples
use async_trait::async_trait;
use clap::{ArgMatches, Command};
use cot::cli::{Cli, CliTask};
use cot::project::WithConfig;
use cot::{Bootstrapper, Project};

struct Frobnicate;

#[async_trait(?Send)]
impl CliTask for Frobnicate {
    fn subcommand(&self) -> Command {
        Command::new("frobnicate")
    }

    async fn execute(
        &mut self,
        _matches: &ArgMatches,
        _bootstrapper: Bootstrapper<WithConfig>,
    ) -> cot::Result<()> {
        println!("Frobnicating...");

        Ok(())
    }
}

struct MyProject;
impl Project for MyProject {
    fn register_tasks(&self, cli: &mut Cli) {
        cli.add_task(Frobnicate)
    }
}
Source

fn register_apps(&self, apps: &mut AppBuilder, context: &RegisterAppsContext)

Registers the apps for the project.

§Examples
use cot::project::{AppBuilder, RegisterAppsContext};
use cot::{App, Project};

struct MyApp;
impl App for MyApp {
    fn name(&self) -> &str {
        "my_app"
    }
}

struct MyProject;
impl Project for MyProject {
    fn register_apps(&self, apps: &mut AppBuilder, context: &RegisterAppsContext) {
        apps.register(MyApp);
    }
}
Source

fn auth_backend(&self, context: &AuthBackendContext) -> Arc<dyn AuthBackend>

Sets the authentication backend to use.

Note that it’s typically not necessary to override this method, as it already provides a default implementation that uses the auth backend specified in the project’s configuration.

§Examples
use std::sync::Arc;

use cot::auth::{AuthBackend, NoAuthBackend};
use cot::project::AuthBackendContext;
use cot::{App, Project};

struct HelloProject;
impl Project for HelloProject {
    fn auth_backend(&self, context: &AuthBackendContext) -> Arc<dyn AuthBackend> {
        Arc::new(NoAuthBackend)
    }
}
Source

fn middlewares( &self, handler: RootHandlerBuilder, context: &MiddlewareContext, ) -> RootHandler

Returns the middlewares for the project.

This method is used to return the middlewares for the project. The middlewares will be applied to all routes in the project.

§Examples
use cot::Project;
use cot::middleware::LiveReloadMiddleware;
use cot::project::{MiddlewareContext, RootHandler, RootHandlerBuilder};

struct MyProject;
impl Project for MyProject {
    fn middlewares(
        &self,
        handler: RootHandlerBuilder,
        context: &MiddlewareContext,
    ) -> RootHandler {
        handler
            .middleware(LiveReloadMiddleware::from_context(context))
            .build()
    }
}
Source

fn error_handler(&self) -> DynErrorPageHandler

Returns the error handler for the project.

The default handler returns a simple, minimalistic error page that displays the status code canonical name and a generic error message.

§Errors

This method may return an error if the handler fails to build a response. In this case, the error will be logged and a generic error page will be returned to the user. Because of that, you should avoid returning an error from this handler and try to handle the error gracefully instead.

§Panics

Note that this handler is exempt from the typical panic handling machinery in Cot. This means that if this handler panics, no response will be sent to a user. Because of that, you should avoid panicking here and return Err instead.

§Examples
use cot::Project;
use cot::error::handler::{DynErrorPageHandler, RequestError};
use cot::html::Html;
use cot::response::IntoResponse;

struct MyProject;
impl Project for MyProject {
    fn error_handler(&self) -> DynErrorPageHandler {
        DynErrorPageHandler::new(error_handler)
    }
}

async fn error_handler(error: RequestError) -> impl IntoResponse {
    Html::new(format!("An error occurred: {error}")).with_status(error.status_code())
}

Implementors§