Why Rust Is Not Suitable for Developing Web APIs

Why Rust Is Not Suitable for Developing Web APIs
Author | Tom MacWright
Translator | Wu Liupo
Editor | Cai Fangfang

Rust is a magical programming language with excellent CLI tools, such as ripgrep and exa. Companies like Cloudflare are using and encouraging people to write Rust to run microservices. Software written in Rust can be safer, smaller, and more concise than C++ or C.

If I am writing a geocoder, a routing engine, a real-time messaging platform, a database, or a CLI tool, Rust is the most suitable.

But last year, I tried to write a pure API service for a traditional website with Rust, and it was not suitable.

1Missing Many Small Features

Rust has a lot of web service frameworks, database connectors, and parsers. However, there are only very low-level components for building authentication services. Node.js has passport.js, Rails has devise, and Django has out-of-the-box authentication models, but in Rust, you need to learn how to convert a shared Vec to the underlying cryptographic library to build this system. (Translator’s note: Vec is a dynamic array that only grows automatically and does not shrink automatically. Unlike Array, Vec has the ability to dynamically add and remove elements and can access items in O(1) time. All items in a Vec are generated on the heap, allowing easy movement of a Vec out of a stack without worrying about memory copy affecting execution efficiency, as it only copies the pointer on the stack.) Some libraries try to solve this problem, like libreauth, but it is still in its early stages of development. There are many similar issues with web frameworks.

What about SDKs? In mainstream programming languages, you can connect to Google Cloud, AWS, or Stripe through an official library. Most of these official libraries are excellent. For example, aws-sdk-js and the Stripe library are well-designed and maintained.

Rust does not have this; there are only a few third-party libraries, but with the development speed of these services, can they really provide a high-quality experience?

Some may say, “Well, X programming language is so good, you can write an SDK yourself over the weekend!” I must respond, no.

The ecosystem of Rust is very rich in other areas. The crates for building CLI applications, managing concurrency, using binary data, and underlying parsers are impressive and fantastic.

2The Rust Compiler Is Faster Than Before, But Still Slow

I have been following Nicholas Nethercote‘s blog, which describes how the Rust team is optimizing the compiler to make it faster!

However, compared to other programming languages, building a website with it will be slow. It is much slower than compiled languages like Go and significantly slower than interpreted languages like JavaScript, Ruby, and Python.

Once the code is compiled, everything becomes fantastic! But in my case, even basic API functionality was incomplete, and a non-complex system took over 10 minutes to compile. The hardware configuration for Google Code builds is poor, and it always times out, leaving me unable to compile anything.

As long as you don’t rebuild cached dependencies, caching makes sense. Perhaps reducing dependencies will speed up Rust project compilation. But like serde, almost everyone uses it for JSON and other serialization/deserialization, which takes up a lot of compile time. Should we replace serde with something that compiles faster but lacks extensive documentation and ecosystem support? This trade-off is terrible.

3Rust Is Complex

Rust forces you to think about code dimensions, which is very important for system programming. It makes you think about how to share or copy memory, consider real but unlikely low-probability events, and ensure they are handled properly, helping you write various efficient codes.

These concerns are valid, but for most web applications, they are not the most important focus, and thinking in popular inertia can lead to incorrect assumptions.

Take the safety of Rust as an example. This is an important part of its tagline, and it is absolutely true: Rust promises both safety and low-level capabilities—it can work without a garbage collector while preventing memory-based vulnerabilities. When you read “safety,” think of C, its competitor. Code in C can reference any memory, making it easy to overflow and make mistakes. Rust code can be as fast as C code but can protect memory access without needing a garbage collector or some runtime checks.

However, Rust‘s memory rules are no safer than Node.js or Python. Web applications written in Rust are not safer on the system than those written in Python or Ruby. High-level programming languages with garbage collectors often incur performance losses to avoid such vulnerabilities and errors. You cannot reference uninitialized memory in JavaScript because JavaScript does not perform memory referencing between references.

As a side note: this describes the design goals of Node.js and other systems—they do occasionally have bugs. The caching objects in Node.js are worth reading.

If you ask some people, they will say that if unsafe code is used, Rust is less safe than programming languages with memory reclamation—including the most popular web framework Actix (Translator’s note: Actix is an asynchronous concurrency framework for Rust based on Tokio and Future, featuring asynchronous non-blocking event-driven concurrency capabilities with a low-level actor model to provide lock-free concurrency and synchronous actors, making it fast, reliable, and easy to scale https://actix.rs/), because unsafe code allows the use of raw pointers.

If you are writing a video game, pausing execution for garbage collection is not good. If you are writing microcontroller code, any memory “overhead” or waste is terrible. However, most web applications can afford to save a little memory overhead for production performance.

The other properties of Rust face similar controversies. Its concurrency features are fantastic, and if you are doing something complex that requires quick responses, that is certainly great. But what if that is not the case? At the very least, Rust‘s asynchronous ecosystem faces significant challenges: there are different asynchronous implementations in various unrelated domains, such as tokio.

In contrast, Python‘s Tornado and Twisted asynchronous implementations are quite strange, while Node.js‘s asynchronous implementation is very good, but the syntax is ugly.

I am confident that Rust‘s asynchronous will stabilize and unify, making it easier to operate in the future, but I need to use it now.

4The Rust Ecosystem Is Not Web-Centric

Many people are learning Rust, writing CLI applications or low-level code, and having a great time. However, significantly fewer people are writing ordinary web applications in Rust.

This is an important part of technical selection: is anyone using the tool? Are they roughly in the same field? Unfortunately, much of the incredibly exciting work in the Rust ecosystem is unrelated to web application servers. There are indeed some promising web frameworks—even higher-level frameworks—but undoubtedly, their market is small. Even the major web framework Actix has only a few top contributors.

If Rust continues to grow at its current rate, the web part of the community will reach a critical mass, but I believe there are not enough people using Rust as a practical tool for websites. Compared to other communities, many companies are committed to using existing tools to build web applications, which are not cutting-edge but are sufficient to differentiate mature technologies from new ones.

5Juniper’s N+1 Query

This section is not just about Rust; it also involves the GraphQL ecosystem, and Rust‘s participation in this ecosystem is an example.

The N+1 problem is something everyone building web applications should know. The point is: you have a page of photos (one query), and you want to display the authors of each photo. How many queries will there be: 1, merging photos and authors, or querying each photo for its author after retrieving the photos? Or two, the second query retrieves the authors from the user IDs, getting all authors at once, and then reassigning their photo properties.

N+1 queries are typically prioritized to be solved at the database level: for example, converting N+1 queries into a single query can lead to significant performance optimizations. We have many ways to try and solve these problems: you can write SQL and try to do a lot of work in a single query using CTE and JOIN, as we do in Observable, or use an ORM layer like ActiveRecord to convert N+1 queries into predictable queries quickly.

Juniper is a GraphQL service for Rust applications. GraphQL is primarily defined by front-end applications rather than back-end. Give it a set of things that can be queried, and the application (like React or others) will send arbitrary queries to the back end.

This complicates the back end. Any optimization at the SQL level is impossible—your server is writing dynamic SQL, and optimization can only rely on the GraphQL service, but it won’t always be effective. For example, Juniper performs N+1 queries by default, and the solution, dataloader, is still rough and needs to be maintained separately. Therefore, in the end, you will have a very fast application layer, but all its time will be spent on extremely inefficient database queries.

In summary, GraphQL works very well with NoSQL databases, providing rapid service for these types of requests. I am confident that Facebook has some specific databases that work excellently with GraphQL, but other companies in the industry heavily rely on Postgres and similar products.

6Some Considerations

First, the issues mentioned in this article do not target using Rust in general scenarios but rather using Rust for specific goals and ecosystems, simply put, web APIs.

Consideration 1: Generally, you can build a website with any programming language. Remember the OkCupid implemented in C++? (Translator’s note: OkCupid is a large online dating site in the US.) There is also a very popular astrology application, Co-star, which is entirely written in Haskell. If you are proficient in other programming languages or can hire engineers skilled in these languages, you can still succeed.

Consideration 2: What I attempted to build was a heavy CRUD (Create, Read, Update, Delete) web application API. It may not count as a web “service”—mainly executing the same operation quickly and numerous times, but rather a web “application”—performing many different operations and containing quite a bit of business logic. If what you are developing is different from what I am doing, my advice may not be suitable for you. If you need to execute one or two operations quickly, like writing a payment gateway or voice messaging application, then Rust might work quite well.

Consideration 3: This article was written in January 2021, and if the community continues to develop, Rust will receive continuous improvements and become better and easier for web application development.

In summary, I really enjoy using Rust; it is a beautiful programming language with many cool ideas. I hope that soon Rust will become the most suitable tool for building what I want to create. However, many things I want to do now require different programming languages with different features to run better.

Link to the Original English Text:
https://macwright.com/2021/01/15/rust.html
Today’s Recommended Articles
2021 Becomes the Year of Rust! Facebook, Microsoft, Google, and Amazon Compete for Rust Talent
A 15-Year Veteran from Huawei Talks About Enterprise Innovation Methodology: Value Creation, Strategic Determination, Value Distribution
After Continuous Bans, What Are the “TikToks” Going Abroad Still Persisting In?
Weekly Highlights Now Available on Mobile, Subscribe Immediately to Receive
A Collection of Essential Content for InfoQ Users Every Week:
Global IT News Written or Compiled by Senior Technical Editors;
Practical Technical Cases Written by Frontline Technical Experts;
Courses and Technical Events Registration Channels Produced by InfoQ;
Follow Now, Subscribe to Weekly Fresh News

Why Rust Is Not Suitable for Developing Web APIs

Tap to View Less Bugs👇

Leave a Comment