Axum vs Loco

注意:Loco 基于 Axum,它是 "Axum 加电池",非常容易将您的 Axum 代码迁移到 Loco。

我们将研究 realworld-axum-sqlx ,这是一个基于 Axum 的应用,它试图描述一个真实世界的项目,使用 API、真实数据库和真实世界场景,以及真实世界的可操作性需求,例如配置和日志记录。

我们将逐个剖析 realworld-axum-sqlx展示将其从 Axum 迁移到 Loco 后,大部分代码已经为您编写完成,您将获得更好的最佳实践、更好的开发体验、集成的测试、代码生成,并更快地构建应用。

您可以使用此分解 来了解如何将您自己基于 Axum 的应用迁移到 Loco。如有任何问题,请在 discussions 中提出,或点击 绿色邀请按钮 加入我们的 discord。

main

当使用 Axum 时,您必须拥有自己的 main 函数,该函数设置应用的每个组件,获取您的路由器,添加中间件,设置上下文,并最终在套接字上设置 listen

这是大量手动且容易出错的工作。

在 Loco 中,您:

  • 在配置中切换所需中间件的开启/关闭
  • 使用 cargo loco start,完全不需要 main 文件
  • 在生产环境中,您将获得一个名为 your_app 的已编译二进制文件,您可以运行它

迁移到 Loco

  • 在 Loco 的 config/ 中设置您需要的中间件
server:
  middlewares:
    limit_payload:
      body_limit: 5mb
  # .. 更多中间件在下方 ..
  • 在 Loco 的 config/ 中设置您的服务端口
server:
  port: 5150

结论

  • 无需编写代码,除非必须,否则您不需要手动编写 main 函数
  • 开箱即用的最佳实践,您将获得一个 main 文件的最佳实践,在您的所有 Loco 应用中统一共享
  • 易于更改,如果您想删除/添加中间件来测试,只需在配置中切换开关,无需重新构建

Env

realworld axum 代码库使用 dotenv,需要在 main 中显式加载:

 dotenv::dotenv().ok();

并且需要一个可用的、已维护和加载的 .env 文件:

DATABASE_URL=postgresql://postgres:{password}@localhost/realworld_axum_sqlx
HMAC_KEY={random-string}
RUST_LOG=realworld_axum_sqlx=debug,tower_http=debug

这是一个项目附带的 示例 文件,您必须手动复制和编辑,这通常非常容易出错。

迁移到 Loco

Loco:使用您的标准 config/[stage].yaml 配置文件,并使用 get_env 从环境中加载特定值

# config/development.yaml

# Web 服务器配置
server:
  # 服务器监听的端口。服务器绑定为 0.0.0.0:{PORT}
  port: {{% get_env(name="NODE_PORT", default=5150) %}}

此配置是强类型的,包含最常用的值,如数据库 URL、日志记录器级别和过滤等。无需猜测或重新发明轮子。

结论

  • 无需编码,迁移到 Loco 时,您编写的代码更少
  • 更少的活动部件,仅使用 Axum 时,除了环境变量外,您还必须进行配置,这是您使用 Loco 可以免费获得的东西

数据库

仅使用 Axum,您通常必须设置您的连接、连接池,并将其设置为可用于您的路由,以下代码是您通常放在 main.rs 中的:

    let db = PgPoolOptions::new()
        .max_connections(50)
        .connect(&config.database_url)
        .await
        .context("could not connect to database_url")?;

然后您必须手动连接此连接

 .layer(AddExtensionLayer::new(ApiContext {
                config: Arc::new(config),
                db,
            }))

迁移到 Loco

在 Loco 中,您只需在 config/ 文件夹中设置连接池的值。我们已经选择了尽力而为的默认值,因此您不必这样做,但如果您想这样做,可以参考以下配置:

database:
  enable_logging: false
  connect_timeout: 500
  idle_timeout: 500
  min_connections: 1
  max_connections: 1

结论

  • 无需编写代码 - 让您免于为数据库连接池选择正确的值或错误配置它的风险
  • 易于更改 - 通常您想在生产环境中不同的负载下尝试不同的值,仅使用 Axum,您必须重新编译、重新部署。使用 Loco,您可以设置配置并重启进程。

日志记录

在您的应用中,您将不得不手动编写日志记录的故事。您选择哪一个?tracing 还是 slog?是日志记录还是追踪?哪个更好?

以下是 real-world-axum 项目中存在的内容。在服务中:

  // 启用日志记录。使用 `RUST_LOG=tower_http=debug`
  .layer(TraceLayer::new_for_http()),

main 中:

    // 初始化日志记录器。
    env_logger::init();

以及在各个点的临时日志记录:

  log::error!("SQLx error: {:?}", e);

迁移到 Loco

在 Loco 中,我们已经回答了这些难题,并提供了多层日志记录和追踪:

  • 在框架内部,内部地
  • 在路由器中配置
  • 低级别数据库日志记录和追踪
  • Loco 的所有组件,如任务、后台作业等,都使用相同的工具

我们选择了 tracing,以便任何和每个 Rust 库都可以统一“流”入您的日志。

但我们也确保创建智能过滤器,这样您就不会被默认情况下不了解的库轰炸。

您可以在 config/ 中配置您的日志记录器

logger:
  enable: true
  pretty_backtrace: true
  level: debug
  format: compact

结论

  • 无需编写代码 - 没有设置代码,无需做决定。我们为您做出了最佳决定,以便您可以为您的应用编写更多代码。
  • 构建更快 - 您只获得您想要的追踪。您获得彩色、上下文丰富且零噪声的错误回溯,这使得调试更容易。您可以更改生产环境的格式和级别。
  • 易于更改 - 通常您想在生产环境中不同的负载下尝试不同的值,仅使用 Axum,您必须重新编译、重新部署。使用 Loco,您可以设置配置并重启进程。

路由

将路由从 Axum 迁移到 Loco 实际上是直接替换。Loco 使用原生的 Axum 路由器。

如果您想要路由列表和信息等功能,您可以使用原生的 Loco 路由器,它可以转换为 Axum 路由器,或者您可以使用自己的 Axum 路由器。

迁移到 Loco

如果您想要 1:1 完全复制粘贴的体验,只需复制您的 Axum 路由,并将您的路由器插入 Loco 的 after_routes() 钩子:

  async fn after_routes(router: AxumRouter, _ctx: &AppContext) -> Result<AxumRouter> {
      // 使用 AxumRouter 挂载您的路由并返回 AxumRouter
  }

如果您希望 Loco 理解有关您的路由的元数据信息(稍后可能会派上用场),请以这种方式在每个控制器的 routes() 函数中编写:

// 这是人们通常仅使用 Axum 所做的事情
pub fn router() -> Router {
  Router::new()
        .route("/auth/register", post(create_user))
        .route("/auth/login", post(login_user))
}

// 这是使用 Loco 的样子(请注意我们使用 `Routes` 和 `add`)
pub fn routes() -> Routes {
  Routes::new()
      .add("/auth/register", post(create_user))
      .add("/auth/login", post(login_user))
}

结论

  • 即插即用的兼容性 - Loco 使用 Axum 并保持其所有构建块完整,以便您可以直接使用您现有的 Axum 代码,而无需任何努力。
  • 免费的路由元数据 - Axum 路由器的一个缺点是无法描述当前配置的路由,这可以用于列表或自动 OpenAPI 模式生成。Loco 有一个小型的元数据层来支持这一点。如果您使用 Routes,您将免费获得它,同时所有不同的签名都与 Axum 路由器保持兼容。