#axum #service #pattern #framework #web-framework #fig #strangler

axum-strangler

Strangler fig pattern utility crate for the Axum web framework

10 unstable releases (3 breaking)

0.4.0 Dec 12, 2022
0.4.0-rc.5 Dec 5, 2022
0.4.0-rc.3 Nov 27, 2022
0.3.1 Nov 4, 2022
0.1.0 Jul 18, 2022

#2198 in Web programming

MIT/Apache

45KB
796 lines

Axum Strangler

A utility crate to be able to easily use the Strangler Fig pattern with the Axum crate without having to use some sort of gateway.

Goal of the crate

To support the usecase where you want to rewrite services in Rust, but you can't justify the cost of migrating everything over all at once. With the Strangler, you can put the Rustified service in front of the service you want to migrate, and out of the box, almost everything should still work. While migrating you slowly add more logic/routes to the Rust service and automatically those routes won't be handled by the service you're migrating away from.

Example

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // We want to forward requests we don't handle ourselves to localhost:3333
    let strangler_svc = axum_strangler::Strangler::new(
        axum::http::uri::Authority::from_static("127.0.0.1:3333"),
    );

    // Add it as a fallback so everything that isn't covered by routes, get forwarded to the strangled service.
    let router = axum::Router::new()
        .route("/hello",  get(|| async { "Hello, World!" }))
        .fallback_service(strangler_svc);

    axum::Server::bind(&"127.0.0.1:0".parse()?)
        .serve(router.into_make_service())
        .await?;
    Ok(())
}

Feature flags

nested-routers

If you are using an axum router nested inside of another one, the route forwarding will not work as expected, as the path that get's forwarded is only the piece of the path defined in the nested router, not the entire path (so if you nest a router at /api, all requests would be forwarded without the /api, and only what comes after it).

To fix this, you can enable the feature flag nested-routers, which will allow it to retrieve the OriginalUri to properly forward it.

https

Allows forwarding to another server that only accepts HTTPS traffic:

let strangler_svc = axum_strangler::Strangler::builder(
    axum::http::uri::Authority::from_static("127.0.0.1:3333"),
).with_http_scheme(axum_strangler::HttpScheme::HTTPS).build();

websocket

Allows the strangler service to also handle websockets, forwarding every message from requester to strangled service and vice versa.

TLS

In order to work with websockets over TLS (wss://), you'll need to enable additional features. You can choose which tokio-tungstenite dependency you use for tls, all of the three following features map on the counterpart there, but all three enable the wss:// protocol:

  • websocket-native-tls
  • websocket-rustls-tls-native-roots
  • websocket-rustls-tls-webpki-roots

tracing-opentelemetry-text-map-propagation

Causes the Strangler to propagate tracing information to the stranglee. This could be useful to gather information about what exactly is going on. This only works if there is an active opentelemetry context in the current tracing span, and you've installed the opentelemetry::sdk::propagation::TraceContextPropagator as the opentelemetry::global::set_text_map_propagator.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~7–22MB
~308K SLoC