back
▲ 488 points

Show HN: Rust Web Framework

github.com
by levkk·1y ago·258 comments·view on hn ↗
Hi everyone,

I've been "funemployed" for a few months and with all that free time and idle hands I wrote a full web framework (think Rails, not Flask) for Rust.

It's boring old MVC, has its own ORM, templates, background jobs, auth, websockets, migrations and more. If you're keen but don't feel like rewriting your app in a different language, Rwf has a WSGI server to run Django (or Flask) inside Rust [1], letting you migrate to Rust at your own pace without disrupting your website.

I think Rust makes a great prototyping and deploy straight to production language. Now it has yet another framework for y'all to play with.

Cheers!

[1] https://levkk.github.io/rwf/migrating-from-python/

258 comments
Nice, congratulations. It must feel so surreal launching this!

One of my biggest learnings from doing a bunch of web MVC through Rails over the years is that the framework should heavily discourage business logic in the model layer.

Some suggestions:

- Don't allow "callbacks" (what AR calls them) ie hooks like afterCreate in the data model. I know you don't have these yet in your ORM, but in case those are on the roadmap, my opinion is that they should not be.

- That only really works though if you not strongly encourage a service aka business logic layer. Most of my Rails app tend to have all of these as command aka service objects using a gem (library/package) like Interactor.*

* It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer.

Also, curious why existing ORMs or query builders from the community weren't leveraged?

Disclaimer: I haven't written a line of Rust yet (more curious as the days go by). I'm more curious than ever now, thanks to you!

> One of my biggest learnings from doing a bunch of web MVC through Rails over the years is that the framework should heavily discourage business logic in the model layer.

I am curious where this comes from, because my thinking is the absolutely opposite. As much business logic as possible should belong in the model. Services should almost all be specific more complex pieces of code that are triggered from the model. Skinny controller, Fat Model, is the logic of code organization that I find makes code the easiest to debug, organize, and discover. Heavy service use end up with a lot of spaghetti code in my experience.

The other part is that from a pure OOP pov, the model is the base object of what defines the entity. Your "User" should know everything about itself, and should communicate with other entities via messages.

> Don't allow "callbacks" (what AR calls them) ie hooks like afterCreate in the data model. I know you don't have these yet in your ORM, but in case those are on the roadmap, my opinion is that they should not be.

This I agree with. Callbacks cause a lot of weird side effects that makes code really hard to debug.

What even is a "model" if it doesn't have business logic? It sounds like you just want your model to be built from structs (that you call models) and procedures (that you call services). You can do that, but it can be quite hard to reason about what ways an entity can be updated, because any number of procedures could do it and all have their own ideas about what the business rules are. At this point your procedures might as well write back to the db themselves and just get rid of the "models".
I do agree that models should not contain bussiness logic. Not having bussiness logic in models is what Martin Fowler and Robert C. Martin call "anemic domain models" and is contrary to how legacy OOP-heavy and pattern-heavy enterprise development used to be.

However, after +20 years of development, I've came to the conclusion that encapsulation is a burden, not a feature and data should be separated from actions that are being performed on that data. It's called data oriented design or data oriented programming, and I am far from the only one that came to the same conclusion.

> * It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer.

This is quite the claim. I despise service objects, personally. They end up scattering things around and hurt discoverability. There are other ways to do modelling that scale very well. There are a few blog posts on it, here's one from someone at Basecamp: https://dev.37signals.com/vanilla-rails-is-plenty/

This is of course very OO which I'm not a huge fan of. Elixir's Phoenix framework, for example, uses "contexts" which is meant to group all related functionality. In short they could be considered a "facade."

In any event, if you like services you like services, they can work, but saying MVC isn't enough for production-grade is a bit misguided.

I do agree that model callbacks for doing heavy lifting business processes is not great, though for little things like massaging data into the correct shape is pretty nice.

Interesting. I’ve rolled my own PHP ORM at work (forbidden from using FOSS libraries like Laravel) and found hooks to be extremely useful. Notably, my programming experience started with PHP for Wordpress which used hooks extensively, so maybe I’m biased.

Mine has a table spec that can translate into a SQL definition or spit out a nicely formatted HTML form. There’s a separate controller that handles all DB connections / CRUD operations, with before- and after-hooks that can easily cross reference with other tables and constraints if needed.

It all works pretty nicely, although I would still switch to Laravel in an instant if I could.

Thanks!

Re: callbacks. They are very nice, when you have CRUD endpoints that modify models directly from JavaScript [1]. It ends up being pretty DRY, especially since you'll find yourself modifying the same model from different places in the code, and without callbacks, you'll have bad data.

Re: service layer. It's a matter of taste, and you can probably avoid it until you're way in the thousands of LOCs. Rails and Django are all about building quickly - that's an advantage you shouldn't give away to your competitors. Service layer is a drag that you may need as an "enterprise".

Re: MVC not production-ready, we know that's not true, but appreciate the hot take, always a good starting point for a great discussion.

Re: existing ORMs, they were not flexible enough. I used ActiveRecord and Django as my inspiration; those are both excellent ORMs, while existing Rust ORMs lean too heavily on type safety in Rust in my opinion. The database should be the source of truth for data types, and the framework should allow for intentional drift.

Hope you get to try Rust soon. I've been using it for years, and I don't want to go back to Python or Ruby, hence this project.

Cheers!

[1] https://levkk.github.io/rwf/controllers/REST/model-controlle...

>* It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer.

How is that so? Can't you add a service layer and call a service from a controller? I don't know about Ruby but for .NET and most Java frameworks this is possible.

To take an example from .NET frameworks, which I am mostly familiar with, you use WebAPI for web applications and MVC for websites. An API just returns data in JSON or whatever form and MVC returns HTML + javascript + whatever media and files.

A controller receives the HTTP request, does some logic, make DB requests, receives models and uses that logic to update a view and serves that view as an HTML file.

Controller - does actions and uses logic

View - describes how the page looks

Model - contains data

Nothing stops the controller to call a service layer which will call a data layer instead of just calling directly the DB.

I would kinda expect REST framework to be able to generate Swagger (aka OpenAPI) definitions out of the box. That's one of the killer features of FastAPI in my opinion.

Also, I don't really understand what is the reason for creating your own ORM instead of integrating with, let's say diesel.rs [0] and what is the reason for inventing your own template language instead of just picking one of the most popular existing template engines [1].

Other than that this project looks really interesting and I will definitely keep an eye on it.

[0] https://diesel.rs/

[1] https://crates.io/categories/template-engine

I tried Diesel years ago, it was too "Rusty" for me. It made you define your schema twice, and couldn't use the same structs for inserts and selects (so 3 times, really). Overall, great first attempt at matching database types to Rust types, but the ORM needs to be more flexible and ergonomic - it's supposed to make writing queries easier, not harder :)

As for templates, writing your own language is almost a right of passage into 30s+ nerd club. I never read the dragon book, but I always wanted to take that class in school. There will always be different implementations of the same thing, and writing this one that mimics very closely what ERB (Rails) does felt right.

https://github.com/poem-web/poem is one Rust framework with swagger definitions out of the box.
As SRE, I got interested in https://levkk.github.io/rwf/migrating-from-python/. On one hand, this is crazy neat you were able to pull it off. On the stability SRE hand, I'm internally screaming. At scale, this should be handled by Reverse Proxy (Caddy, Nginx, Traefik, whatever)
What an amazing name choice, certainly one way to end up at the top of search results :P

To be serious, good job!! Building a good framework is a shockingly large task, and it’s always nice to see people exploring the design space and trying for new ideas.

> (think Rails, not Flask)

I like that... we need more (or better) opiniated frameworks a la rails/django in static languages.

Well done! You could try to get mentioned on https://www.arewewebyet.org/
Based! Django/Rails in a god tier language!

my suggestions:

- async-trait should be stabilized now, so you shouldn't need the macro anymore

- Add opentelemetry integration so we get metrics and tracing out of the box

- use jemalloc for linux targets

Good work! Keep it up!

I've tried to learn Rust but gave up early. Coming from C#, C/C++, Java, Python, Rust seems weird to me.

And it's not the weirdness that discouraged me, is the slowness of accomplishing one task comparing with languages like C#, Java or Python.

And since I mostly do web development these days, ease of use and productivity is paramount for me. True, with Rust there might be a bit more throughput and speed, but judging from latest web frameworks benchmarks both C# and Java tend to do very well in this regard.

Please, don't read this as a critique of Rust, or me trying to take away such a great accomplishment such as writing a MVC framework from scratch, but more of a "proper tool for the proper job" type of post.

Nice got rustpilled myself recently through ditching webpack js loaders and using rust ones which are 50x faster, rust is so preformance enhancing, c++ and rust are my favourite languages atm.
I've been evaluating and building out small prototypes with all the usual suspects for backend Rust work. So far I've reluctantly agreed with the hive mind that Axum on balance is the best choice, despite being lower-level than I'd like.

Other contenders were Loco (but was TOO much like Rails) and Rocket (whose macros only started to bother me after writing more Rust).

Your framework seems to perfectly match my criteria of "batteries-included, but not too prescriptive". Great addition to the ecosystem!

Sounds nice, years of Django dev (with some other dev sprinkled in) has really taught me the value of boring old MVC and the rest of the ingredients, will def be having a look.
Congrats! I have a question: I used to have a job as a Rails developer, and one thing i struggled with was knowing which options/hash keys were possible to pass into various functions, due to the lack of typing. Would it be the case that your framework, based in a type-safe language, would give precise autocompletion of all such options? Or does advanced usage of Rust macros remove some of this ability? Thanks!
Great work!! I was just talking about how this is a major gap in Rust and here you are the very next day! Looking forward to use and contribute!
Honestly, including an ORM as a built-in 'feature' of a web framework seems like a quaintly reasonable idea at first, but I'm 90% certain that eventually it's going to become either (or both):

* it's own project because maintaining it will take up so much of your time.

* be decoupled from the web framework because users will want to use another because your own doesn't have abc feature.

From observing the ecosystems in .NET, Java and PHP, lots of people have lots of opinions on how ORMs should work.

Looks cool! How does it compare to loco.rs?
I just noticed that REST framework returns 501 - Not Implemented [0] if the method is not implemented, which I think is really weird. I think that most frameworks return 405 Method Not Allowed in such cases.

Also, it is typically assumed that 5xx return codes are retryable while 4xx are not. So, I don't think that not implemented method should return 5xx, because it is pointless to retry it.

[0] https://github.com/levkk/rwf/tree/main/examples/rest#restcon...

Another related submission from today:

Ryde: A Rust Web Framework - https://github.com/swlkr/ryde (October 2024, 5 comments)

```I think Rust makes a great prototyping and deploy straight to production language.```

How?

Thanks for this. I've been looking for a Django-esque web-framework for Rust for a while now, and it would seem I'm not the only one[1].

Also, if you're open to suggestions, use SemVar, and have releases on GH so we get email notifications.

[1] https://news.ycombinator.com/item?id=41760421

@levkk How do you thing it compares to loco.rs, I'd like to understand the differences.
Do you plan on adding CRUD generators? That was the killer feature of MVC frameworks
Thanks for sharing!

As a heads-up, The Pages documentation page is blank.

https://levkk.github.io/rwf/controllers/pages/

Cool! Since I learned Rust I've wanted a Django replacement that has the functionality of a batteries included Web Framework + the speed/footprint of Rust. I'll check it out!
> boring old MVC

> Written using the classic MVC pattern (model-view-controller)

well, the "classic web" version I assume. I've never seen a web context in which the original MVC model was used.

Looks great, very interesting! How is the state of to documentation?
Awesome, looking forward to testing it out. I really like that idea of being able to gradually migrate WSGI (Django) apps, or even support running both at the same time.
I can already hear people asking "Did you aRWF already?" Seriously, the migration option is precisely how I think migration for years. Great job!
Does Rust have any DSL for web use (e.g. Rails in someways is a DSL to Ruby)?

I ask because I imagine a simplified (Rust) syntax would be more inviting to newcomers.

I love rust!! This is so cool and I'm a beginner and I'm not sure if I can utilize this framework or not.
Surely it has a WSGI client not a server.
Very interesting. I might have to check this out after work!
Love it; this is a big gap in Rust's ecosystem IMO.
Impressive launch, good luck and happy coding!
> I think Rust makes a great prototyping and deploy straight to production language

Sorry what? Isn't Rusts whole thing is that it prevents you from prototyping wild ideas, in the name of memory safety?

What happened with PostgresML?
This looks very cool!
Hopefully it takes off.
Well done!
After years of working with web frameworks in Python and Java, and then picking up Go along the way, I've come to appreciate Go's approach much more. That is, with a rich and capable standard library, you really don't need traditional frameworks. Need an HTTP server, router, etc.? Use stdlib. Need templates? Use stdlib. Need an ORM? You don't, but you may want to consider a small 3rd party query builder library of your choice. And so on.

This avoids depending on a complex framework that may or may not exist in a few years, improves security by minimizing the amount of 3rd party dependencies, keeps the learning curve low for any new developers joining the project, and is more flexible and easier to maintain. I don't have experience with Rust, and judging by the comments here, web frameworks might still be useful for it. Which is a shame, since the batteries included stdlib approach is far superior IME.

Anyway, I don't want to shoot down your efforts. Congrats on the launch and good luck!

Lately I've been following https://loco.rs/ as it aims for a rails-like experience, complete with generators for workers, controllers, etc. I've only had time to experiment but it's the closest I've gotten to feeling rails-y in rust.