We adopt micro frontend architecture CDN (Fastly) Node.js Article Detail Search Market Article Index connect by anchor tags We love HTTP and HTML … handlebars handlebars VCL + handlebars react split with vertical aggregate
We adopt micro frontend architecture CDN (Fastly) Node.js Article Detail Topic Index Search Market Article Index connect by anchor tags We love HTTP and HTML handlebars handlebars handlebars VCL + handlebars We maintain 24 micro frontend services with limited resource
We adopt micro frontend architecture CDN (Fastly) Node.js Article Detail Topic Index Search Market Article Index connect by anchor tags We love HTTP and HTML handlebars handlebars handlebars VCL + handlebars We maintain 24 micro frontend services with Node.js v12 (current is v21) (Including tooling, we maintain 40↑ projects with old Node.js)
We adopt micro frontend architecture CDN (Fastly) Node.js Article Detail Topic Index Search Market Article Index connect by anchor tags We love HTTP and HTML handlebars handlebars handlebars VCL + handlebars We are now replacing v12 → v16 → v18→ v20 for 11 months 😇
Updating Node.js and library is so hard ● Node.js releases a major update every 6 months. It is frequent. ● We must update Node.js version for EOL. ● After updating Node.js, sometimes (I often experience) fail npm install, or fail building app with bundler. Due to node-gyp, node-sass, --openssl-legacy-provider… 😭 We need maintanability
Should we follow the new lang and lib version? application With UI JSON API Developing Stable Sometimes it needs maintenance e.g. serious security patch, EOL We always doesn’t have to keep up with each new version. Always it needs maintenance
Should we follow the new lang and lib version? application With UI JSON API Developing Stable Sometimes it needs maintenance e.g. serious security patch, EOL We always doesn’t have to keep up with each new version. Always it needs maintenance We considered replacing a new tech stack
Our requirements for the new tech stack are… ● Typing ● Lint ● Test ● OAS (Open API Schema) ● Documentation / Gen Doc ● Clever pkg manager ● Error handling ● Logging / Tracing Rich and modern feature help our maintenance
Rust with Nikkei Some teams at Nikkei adopted Rust in production ● Using Fastly Computing@Edge for delivery and handling access log. ○ access log server handles 6500 req/sec ● Wave BFF Server uses Rust for schemaful endpoint with gRPC and HTTP. ○ Wave: https://hack.nikkei.com/blog/advent20201218/ So I’m in a good environment to choose Rust. But…
Is choosing Rust appropriate? My concern is ● Rust is not batteries-included lang. We must choose 3rd party libs. ○ async runtime ○ web server ○ common util (serializer, date, …) ● Long-term stability of 3rd party ecosystems.
But we chose Rust ● Rust itself is solid ● Although Rust is not batteries-included lang, there are many de facto libs. (e.g. tokio, thiserror, anyhow, chrono…) ● Rust can find breaking changes easily at compile time.
We choose axum as Web FW ● hyper ○ primitive. I need router. ● actix-web ○ good choice ● axum ○ tokio-rs maintain this. I believe maintenance continue to If we choose a web fw, the choices are
HTTP Server with Hyper ● Hyper is a tokio based HTTP library. ● It’s too primitive. (e.g. Hyper doesn’t have a router.) Hyper is not for web app developer but for library developer https://hyper.rs/
Tower provides abstract of req → res ● Official description is `async fn(Request) -> Result` ● Tower provides a trait for creating middleware. ● HTTP Server can be described as composition of middlewares. Router, Auth, Logger, Retry, Rate Limit, Timeout, and so on. https://github.com/tower-rs/tower
Service is a main concept of tower ● Service is an abstract model of processing req -> res. ● Main part is call function. This accepts a request and returns a response future. https://docs.rs/tower/latest/tower/trait.Service.html
● Router is a Tower Service in axum. call return Oneshot which is tower service and have handler Fn. ● Register path and handler ● Handler value is into HTTP Response, the converter is also tower service
Router is a Tower Service in axum ● Router’s role is matching path, and execute handler. ● Router is implemented as tower Service. call finds matched path, and execute handler function. handler is also service. ● Router’s call return RouteFuture. This includes Oneshot struct which impl Future poll of calling handler service. https://docs.rs/axum/latest/axum/struct.Router.html
Handler value is into HTTP Response, the converter is also tower service ● Routing handler is a function. The return value can be HTTP Response with any Status Code. ● IntoResponse trait control it. str and Result and many struct has default IntoResponse impl. So, automatically convert to HTTP. ● Endpoint have MapResponse struct which has into_response Fn. MapResponse is also tower service. The service is called in polling Oneshot. HTTP/1.1 200 OK content-type: text/plain; charset=utf-8 content-length: 13 date: Thu, 19 Oct 2023 03:22:40 GMT Hello, World
I want to avoid tight coupling with axum ● Although axum is popular Web FW, it is 3rd party. ● Sometimes our app may fail updating axum version because of our wrong implement.
Introduce Layered Architecture ● Cargo can manage dependency graph through its workspaces feature.(e.g. controller cannot import repository) ● I recommend you split your application into modules as it grows ● And use axum only in controller and router. entity repository service usecase controller [package] name = "controller" [dependencies] axum = "0.6.20" entity = { path = "../entity" } usecase = { path = "../usecase" }
Separation of cross-cutting concerns ● Separation of cross-cutting concerns with tower. ● Middleware is auth, logging, rate limit, delay, retry and so on. ● Any layer from any framework is reusable if it implements tower interface. axtix-web is not tower based FW. But that middleware is like tower service. https://actix.rs/docs/middleware
Case: Easily move to hyper ● Axum = hyper + tower ● We can use hyper directly ● service_fn transform function to Service ● Axum router’s handler is just function which return &str, Result and so on. It’s reusable. ● For hyper v1, it may need tower-hyper-http-body-compat. Service is general. can run axum router handler
Conclusion ● Although developing HTTP server in Rust require 3rd party FW, Rust would be good choice. ● Most FW use simple function as router, so you can easily replace to each library. ● For replace, let’s adopt layered architecture, and use FW in only router and controller. ● About AOP logic, If we adopt tower interface, we may be able to replace to each library because other library also adopt tower or tower like Service. So I use tower based FW.