Choosing a Rust web framework, 2020 edition

栏目: IT技术 · 发布时间: 4年前

内容简介:This post was originally meant as a section ofAs of July 2020, the main web frameworks in the Rust ecosystem are:

This post was originally meant as a section of Zero To Production to explain the reasoning behind our technology choice. It eventually grew so large to be its own article!

You can discuss the article on HackerNews or r/rust .

As of July 2020, the main web frameworks in the Rust ecosystem are:

Which one should you pick if you are about to start building a new production-ready API in Rust?

I will break down where each of those web frameworks stands when it comes to:

  • ;
  • Community and adoption;
  • Documentation, tutorials and examples;

I will in the end make.

Worth remarking that there are no absolutes: different circumstances (and taste) might lead you to a different pick.

1. Comprehensiveness

actix-web , tide and warp are slim web frameworks: they offer you an HTTP web server, routing logic, middleware infrastructure and basic building blocks and abstractions to parse, manipulate and respond to HTTP requests.

rocket takes a different approach - it aims to be batteries-included: the most common needs should be covered by functionality provided out-of-the-box by rocket itself, with hooks for you to extend rocket if your usecase needs it.

It should not come as a surprise then that rocket ships an easy-to-use integration to manage connection pools for several popular database (e.g. Postgres, Redis, Memcache, etc.) as well as its own configuration system in rocket-contrib , an ancillary crate hosted in rocket ’s own repository.

We can compare them to frameworks available in other ecosystems:

  • actix-web , tide and warp are closer in spirit to Flask from Python or Express from Javascript - they might be opinionated, but they do not ship a configuration management system or an ORM integration out of the box. You are in charge of structuring your API as you deem appropriate, bringing all the necessary crates and patterns into the picture;
  • rocket is closer to Django from Python or Symphony from PHP: a stable and solid core with a set of high-quality in-tree components to fulfill your every day needs when building a solid web application. rocket has still a long way to go to match its peers in breadth and scope, but it is definitely off to a good start.

Of course this is a snapshot of the landscape as of today, but the situation is continuously shifting according to the maintainers’ intentions - e.g. actix-web has slowly been accumulating more and more supporting functionality (from security to session management) in actix-extras , under the umbrella of the actix GitHub organization.

Furthermore, using a slim web framework does not force you to write everything from scratch as soon as the framework is falling short of your needs: you can leverage the ecosystem built by the community around it to avoid re-inventing the wheel on every single project.

2. Community and adoption

Numbers can be misleading, but they are a good conversation starting point. Looking at crates.io , we have:

Framework Total Downloads Daily Downloads
actix-web ~1250k ~3000
rocket ~525k ~1000
warp ~435k ~3000
tide ~47k ~300

The number of total downloads is obviously influenced by how long a framework has been around (e.g. actix-web:0.1.0 came out at the end of 2017!) while daily downloads are a good gauge for the current level of interest around it.

You should care about adoption and community size for a couple of reasons:

  • consistent production usage over years makes it way less likely that you are going to be the first one to spot a major defect. Others cried so that you could smile (most of the time);
  • it correlates with the number of supporting crates for that framework;
  • it correlates with the amount of tutorials, articles and helping hands you are likely to find if you are struggling.

The second point is particularly important for slim frameworks.

You can get a feel of the impact of community size, once again, by looking at the number of results popping up on crates.io when searching a framework name:

Framework # results
rocket 178
actix-web 113
warp 57
tide 20

Will all those crates be relevant? Unlikely.

Will a fair share of them be outdated or unproven? Definitely.

Nonetheless it is a good idea, before starting a project, to have a quick look for functionality you know for a fact you will need. Let’s make a couple of quick examples with features we will be relying on in the email newsletter implementation we are building in Zero To Production :

  • if you need to add Prometheus’ metrics to your API you can get off the ground in a couple of minutes with actix-web-prom or rocket-prometheus , both with thousands of downloads. If you are using warp or tide you will have to write the integration from scratch;
  • if you want to add distributed tracing, actix-web-opentelemetry has your back. You will have to re-implement it if you choose any other framework.

Most of these features are not too much work to implement, but the effort (especially maintenance) compounds over time. You need to choose your framework with your eyes wide open on the level of commitment it is going to require.

3. Sync vs Async

Rust landed its async / await syntax in version 1.39 - a game changer in terms of ergonomics for asynchronous programming.

It took some time for the whole Rust ecosystem to catch up and adopt it, but it’s fair to say that crates dealing with IO-bound workloads are now generally expected to be async-first (e.g. reqwest ).

What about web frameworks?

actix-web adopted async / await with its 0.2.x release, same as warp , while tide was using async / await before its stabilisation relying on the nightly Rust compiler.

rocket , instead, still exposes a synchronous interface. async / await support is expected as part of its next 0.5 release, in the making since last summer .

Should you rule out rocket as a viable option because it does not yet support asynchronous programming?

It depends.

If you are implementing an application to handle high volumes of traffic with strict performance requirements it might be better to opt for an async web framework.

If that is not the case, the lack of async support in rocket should not be one of your primary concerns.

3.1. Futures runtime

async / await is not all sunshine and roses.

Asynchronous programming in Rust is built on top of the Future trait: a future exposes a poll method which has to be called to allow the future to make progress. You can think of Rust’s futures as lazy : unless polled, there is no guarantee that they will execute to completion.

This is often been described as a pull model compared to the push model adopted by other languages, which has some interesting implications when it comes to performance and task cancellation.

Wait a moment though - if futures are lazy and Rust does not ship a runtime in its standard library, who is in charge to call the poll method?

BRON- B ring Y our O wn R untime!

The async runtime is literally a dependency of your project, brought in as a crate.

This provides you with a great deal of flexibility: you could indeed implement your own runtime optimised to cater for the specific requirements of your usecase (see the Fuchsia project or bastion ’s actor framework) or simply choose the most suitable on a case-by-case basis according to the needs of your application.

That sounds amazing on paper, but reality is a bit less glamorous: interoperability between runtimes is quite poor at the moment; mixing runtimes can be painful, often causing issues that are not straight-forward either to triage, detect or solve.

While most libraries should not depend on runtimes directly, relying instead on the interfaces exposed by the futures crate, this is often not the case due to historical baggage (e.g. tokio was for a long time the only available runtime in the ecosystem), practical needs (e.g. a framework has to be able to spawn tasks) or lack of standardisation (e.g. the ongoing discussion on the AsyncRead / AsyncWrite traits - see here and here ).

Therefore picking an async web framework goes beyond the framework itself: you are choosing an ecosystem of crates, suddenly making it much more cumbersome to consume libraries relying on a different async runtime.

The current state of affairs is far from ideal, but if you are writing async Rust today I’d recommend you to make a deliberate choice when it comes to your async runtime.

The two main general-purpose async runtimes currently available in Rust are tokio and async-std .

tokio has been around for quite some time and it has seen extensive production usage. It is fairly tunable, although this results in a larger and more complex API surface.

async-std was released almost a year ago, around the time of async / await stabilization. It provides great ergonomics, while leaving less room for configuration knobs.

crates.io can once again be used as a gauge for adoption and readiness:

Runtime Total Downloads Daily Downloads
tokio ~9600k ~30k
async-std ~600k ~4k

How do frameworks map to runtimes?

Framework Runtime
actix-web tokio
rocket ( 0.5.x ) tokio
tide async-std
warp tokio

4. Documentation, tutorials and examples

Having to dive into the source code to understand how something works can be fun (and educational!), but it should be a choice, not a necessity.

In most situations I’d rather rely on the framework being well-documented, including non-trivial examples of relevant usage patterns.

Good documentation, tutorials and fully-featured examples are mission-critical if you are working as part of a team, especially if one or more teammates are not experienced Rust developers.

Rust’s tooling treats documentation as a first class concept (just run cargo doc --open to get auto-generated docs for your project!) and it grew to be part of the culture of the Rust community itself. Library authors generally take it seriously and web frameworks are no exception to the general tendency: what you can find on docs.rs is quite thorough, with contextual examples where needed.

rocket and actix-web provide high-level guides on the respective websites and all frameworks maintain a rich collection of examples as part of their codebases.

Tutorials outside of the project documentation are mostly a function of age: it’s very easy to find material (articles, talks, workshops) on actix-web and rocket while the offering is somewhat more limited for warp and tide . On the flip side, some of what is out there for actix-web and rocket might target older versions, leaving room for confusion.

5. API and ergonomics

Well, difficult to give an opinion on API design that sounds legitimately objective.

We all have wildly different tastes when it comes to what we consider a pleasant API and there is no substitute for a quick hack-and-go to really get a feel for what it is like to use a certain web framework.

If you are short on time, you can have a look at worked out examples: actix-web’s examples , warp’s examples , tide’s examples and rocket’s examples .

If you are curious about warp and tide , Image decay as a service provides an in-depth analysis of their APIs.

6. Our choice

As of July 2020, I’d suggest picking actix-web if you are writing a production API in Rust.

To recap what we covered, actix-web :

  • has seen extensive production usage;
  • relies on tokio as its async runtime, thus minimising the likelihood of compatibility issues with the most popular crates in the async ecosystem;
  • boasts a significant collection of mature plugins as well as the largest community.

While some of its APIs are definitely not the most ergonomic (I am looking at you, Transform trait), the inconvenience is definitely minor all things considered.

On the flip side, Rust itself would not be where it is today if nobody had been willing to take a bet on a promising but less proven technology:

  • tide and warp are pushing the boundary of what is possible in terms of ergonomics using async Rust;
  • the upcoming rocket release is going to be massive, both for its adoption of async / await as well as for the migration from nightly to the stable Rust compiler.
A rising tide lifts all boats.

The way of saying from which tide takes its name, the way forward for the whole Rust async ecosystem.

See you again in a year for another overview!

Thanks to o0Ignition0o and vertexclique for taking the time to review the draft of this article.

If you want to be notified when new articles are released on this blog, subscribe to the email newsletter .


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

民事诉讼程序研究

民事诉讼程序研究

乔罗威茨 / 吴泽勇 / 2008-6 / 40.00元

《民事诉讼程序研究》共分为诉讼程式;扩散利益、分散利益和集体利益的保护;程式样式;当事人与法官;对判決的救济;程式改革。主要內容包括:民事诉讼;英美民事诉讼程式在20世纪的若干发展;论民事诉讼法的本质和目的等。一起来看看 《民事诉讼程序研究》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具