#routes #match #routing #http #utility #path #context-agnostic

route_match

一种基于宏的简单直观的 http 路由实用工具

1 个不稳定版本

新功能 0.2.0 2024年8月23日

#20 in #match

Apache-2.0

10KB

路由匹配

使用宏进行简单直观的http请求路由的实用工具。

快速示例

使用 route_match,您可以这样路由请求

use route_match::route;

fn handle_request(reqest: Request) -> Response {
  route! {
    match (&reqest.method().as_str(), &reqest.uri().path()) {
      GET /foo/bar => handle_foo_bar(),
      POST /user/:id => handle_post_user(request, id),
      _ => handle_404_error(request),
    }
  }
}

目标

HTTP 路由应该很简单。HTTP 协议在 1996 年达到 1.0 版本 - 它是一种非常成熟的技术,基于 URL 和 HTTP 方法进行路由,并从 URL 路径中提取变量,这个问题现在应该已经得到了很好的解决。

在我的经验中,现有的路由解决方案经常遇到一些陷阱,使得这个过程比本来应该要复杂。

  • 它们通常过于 紧密耦合到单一解决方案。一个库可能有很好的路由解决方案,但如果你想使用它,就必须采用它们选择的网络堆栈的其他组件。如果你想要将你的 API 移动到不同的环境中,比如云函数,那里的请求和响应类型受到限制,这并不总是容易。

  • 它们通常是“魔法般”的,由于大量使用特质,可能很难 理解,可能会给出令人困惑的错误信息,并且可能需要花费时间来学习使它们工作的“魔法词汇”。

  • 它们通常 带有局限性。当你需要将解决方案压缩通过路由接口时,你可能会遇到处理生命周期或异步的问题,这些问题可能没有被库作者预料到或围绕这些问题设计。

  • 它们通常 带有运行时成本。路由对象通常会在堆上表示为一个对象,这需要迭代。诚然,这是一个非常非常小的问题,但不必是这样的。

因此,route_match旨在解决这些问题,并为 Rust 中的 HTTP 请求路由提供一个 简单易用、直观、环境无关 的解决方案。

本项目的优先级是

  1. 通过过程宏提供易于使用、直观的 DSL 以路由 HTTP 请求

  2. 让你以 HTTP 协议而非 Rust 语法来思考你的端点

  3. 在您拥有 HTTP 方法和 URL 路径的任何环境中工作,而不管您使用的其他工具或堆栈如何

  4. 专注于单一用例,并做好它。这个库并不试图解决所有可能的路由场景,它旨在处理最常见的场景,同时保持精简、最小化、快速下载和快速构建。

使用方法

以下是一个简单的匹配语句示例

fn match_route(method: &str, path: &str) -> boolean {
    route! {
      match (method, path) {
        GET /foo => true,
        _ => false,
      }
    }
}

match_route("GET", "/foo") // returns true
match_route("GET", "foo") // also true - the leading '/' is optional
match_route("POST", "/foo") // returns false - the method must match
match_route("GET", "/bar") // returns false - the path must match
match_route("GET", "/foo/bar") // returns false - the uri path must match completely

提供的方法和路径将按顺序进行检查,并执行第一个匹配的分支。例如,对于如下匹配表达式

fn match_route(method: &str, path: &str) {
    route! {
      match (method, path) {
        _ /foo -> println!("ANY /foo"),
        GET /foo => println!("GET /foo"),
        _ => println!("default"),
      }
    }
}

match_route("GET", "/foo") // prints "ANY /foo"

条件 GET /foo 将永远不会被执行,因为 _ /foo 也匹配了 GET 条件。

注意,默认的 _ 分支必须始终提供。

URL 路径参数

我们还可以通过在路径模式中插入模式 :var_name 来提取 URL 参数。

fn match_route(method: &str, path: &str) -> boolean {
    route! {
      match (method, path) {
        GET /user/:id => println!("user id: {}", id),
        _ => println!("default"),
      }
    }
}

match_route("GET /user/456") // prints: "GET /user/456"

在这里,id 参数作为 &str 传递给分支表达式。参数的生存期与传递给匹配表达式的 path 参数的生存期相同。

通配符匹配

有时我们想忽略模式的一部分,并 inclusively 匹配

fn match_route(method: &str, path: &str) -> boolean {
    route! {
      match (method, path) {
        // Match any method, so long as the path matches "/foo"
        _ /foo => println!("Any /foo"),
        // Match any request with the method "OPTIONS"
        OPTIONS _ => println!("OPTIONS"),
        // Mathc any path starting with "/foo/bar"
        // Here "rest" will be bound as an &str containing everything
        // in the path following "/foo/bar"
        GET /foo/bar/*:rest => println("rest: {}", rest),
        // Match any method/path combination at all
        _ => println!("default"),
      }
    }
}

语法

route 宏提供了一个匹配表达式,允许您匹配 HTTP 方法和解析模式。

匹配语句的形式为

match_stmnt : match ( , ) { } 方法: 表达式 路径: 表达式

在这里,methodpath 参数可以是任何具有类型 &str 的表达式。

branches 扩展为以下内容

branches : , ? | ? 分支:=> 表达式

pattern : | _ 方法: GET | HEAD | POST | PUT | DELETE | CONNECT | OPTIONS | TRACE | PATCH | _ uri:<uri_components> | " <uri_components> " | _

uri_components : / <uri_component> <uri_components>? | / <uri_component>? uri_component:标识符 | : 标识符

运行时规范

在运行时,匹配语句执行第一个分支表达式,以便提供的方法和路径与分支模式匹配。

依赖项

~270–720KB
~17K SLoC