20 ms·
Show HN: Rust Web Framework
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/ https://levkk.github.io/rwf/migrating-from-python/
- alberth 2y agoDoes 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.
- levkk 2y agoYup, they are called "macros". Rwf uses a few of them, some of which you'll find familiar, e.g. `render!` which returns a rendered template with HTTP 200 [1]. [1] https://levkk.github.io/rwf/views/templates/templates-in-controllers/ https://levkk.github.io/rwf/views/templates/templates-in-con...
- alberth 2y agoThat's good to know. From the ReadMe example, is there a way to use macros to simplify the following line of code: async fn handle(&self, request: &Request) -> Result<Response, Error> { I ask because many web developers don't come from a C/C++/Rust background - so the line above will be jarring/off-putting to many. (Awesome project btw)
- levkk 2y agoThanks! Yes, I was thinking of adding a shorthand for that. Will add something soon!
- degurechaff 2y agofor controller routing. I think pavex have great idea (https://www.lpalmieri.com/posts/pavex-progress-report-02/ https://www.lpalmieri.com/posts/pavex-progress-report-02/) for using rustdoc json
- fkyoureadthedoc 2y agoYou might be surprised, with Typescript's ubiquity in the web space the type definitions probably won't be too scary. I've never used Rust but I assume `&` is some kind of Rusty pointer.
- Scarblac 2y agoComing from Typescript that doesn't look very ominous to me, though it would nice if the types could be inferred somehow.
- afavour 2y agoRust can be an intimidating language but the example you’ve provided there really shouldn’t be intimidating to anyone that’s using TypeScript today. There’s a little learning to with &self and & but that’s really basic Rust stuff. I don’t think it’s wise for a framework to attempt to hide core components of the language.
- sureglymop 2y agoLooks great, very interesting! How is the state of to documentation?
- levkk 2y agoNot bad, but can be improved. I've been putting work into it lately, will keep adding more. Lots of examples in the repo as well.
- ratedgene 2y ago[flagged]
- levkk 2y agoI'm old too, this is how I pretend to stay young.
- mmontagna9 2y agoThe youngest old man I know at any rate
- ratedgene 2y agoUnderstandable. I wasn't criticizing your product -- best of luck and congrats on shipping :)
- Klonoar 2y agoThese kinds of comments seem to be like a fire starter on this site, but I cannot for the life of me see how they fit in the site guidelines. (At some point this place has to contend with the issue of “we started as people trying to build cool things and wound up with every thread being nonstop complaints or nitpicking”.)
- nwnwhwje 2y agoWell done! You could try to get mentioned on https://www.arewewebyet.org/ https://www.arewewebyet.org/
- trevor-e 2y agoVery surprising this page doesn't mention loco.rs which seems like the most "Rails" Rust framework out there.
- giancarlostoro 2y agoVery interesting. I might have to check this out after work!
- notamy 2y agoWhat 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.
- alberth 2y ago> What an amazing name choice "Row" would be another good name choice, that would also be easier to say than 'rwf'. RustOnWeb.com is even able to buy for $10 :) Just say'n
- dankwizard 2y agoNot anymore, squatted : - )
- rafram 2y agoRust projects tend to go for these broad, generic, self-aggrandizing names, and I honestly think it’s a huge mistake. Crates.io is just going to become a graveyard of abandoned projects squatting on legit-sounding names.
- iknowstuff 2y agosuch as?
- binarycoffee 2y agohttps://crates.io/crates/x https://crates.io/crates/x
- Havoc 2y agoHopefully it takes off.
- kvirani 2y agoNice, 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!
- sodapopcan 2y ago> * 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/ 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.
- jt2190 2y agoIt would help a lot if you would clarify what you mean by “service object”. In my experience a single method on a service object would define a transaction. Is that what you mean by “service object”?
- JodieBenitez 2y ago> (think Rails, not Flask) I like that... we need more (or better) opiniated frameworks a la rails/django in static languages.
- tommaho 2y agoThanks for sharing! As a heads-up, The Pages documentation page is blank. https://levkk.github.io/rwf/controllers/pages/ https://levkk.github.io/rwf/controllers/pages/
- throwaway313373 2y agoI 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/ https://diesel.rs/ [1] https://crates.io/categories/template-engine https://crates.io/categories/template-engine
- levkk 2y agoI 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.
- the__alchemist 2y agoSame: I was put off by keeping track of models in triplicate, and the lack of automatic migrations. These are considered features, vice bugs; it's not for me.
- phibz 2y agoI tried diesel about 5 years ago. I needed to do relationships where the foreign key lived on the other side of the relationship from what diesel wanted. IIRC diesel only supported the key on a specific side, I think it was a M:1 relationship. Diesel docs said this was unsupported. I was still learning traits at the time but navigating how to implement this in diesel was beyond me. I used sqlx and moved on.
- taikahessu 2y agoImpressive launch, good luck and happy coding!
- the__alchemist 2y agoLove it; this is a big gap in Rust's ecosystem IMO.
- culi 2y agoIs it? Asking as someone not very tuned into the ecosystem. Based on TechEmpower's Web Framework Benchmarks[0] and AreWeWebYet's resounding "yes!" for years now[1] I always got the impression that there were quite a few options available. Rocket, Actix, Axum, Salvo, etc just to name a few. Each with different focuses (e.g. performance vs "batteries-included-ness") [0] https://www.techempower.com/benchmarks/#hw=ph&test=composite§ion=data-r22 https://www.techempower.com/benchmarks/#hw=ph&test=composite... [1] https://www.arewewebyet.org/ https://www.arewewebyet.org/
- the__alchemist 2y agoGreat question! The frameworks you listed are not a direct comparison to this lib, nor Rails, nor Django. They are Flask analogs. They are ideal for microservices, but are not a substitute for a batteries-included framework of the sort used in websites. I love rust, but don't use it for web backends because there is nothing on Django's level.
- stackskipton 2y agoHow many people are greenfield new Django style projects? I know Static Server-Side Rendering is becoming new hotness but I still thought pure Server-Side Rendering is frowned upon. Most of SSR I see is still SPA + Rest API/GraphQL backend with some scraper generating all the HTML.
- the__alchemist 2y agoThis is orthogonal; You don't use auth, email, automatic admin, migrations etc from a SPA; those are backend jobs.
- cchance 2y ago
- oldpersonintx 2y ago[dead]
- hkc88hkc 2y agoWell done!
- jpopesculian 2y agoLooks cool! How does it compare to loco.rs?
- MASNeo 2y agoI can already hear people asking "Did you aRWF already?" Seriously, the migration option is precisely how I think migration for years. Great job!
- sea-gold 2y ago[flagged]
- culi 2y agoOr any of these XD https://www.arewewebyet.org/topics/frameworks/ https://www.arewewebyet.org/topics/frameworks/
- internetter 2y ago[flagged]
- apbytes 2y agoGreat 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!
- xyst 2y agoWhat are these projects missing that you feel there’s a “major gap” in the web framework space? rocket.rs, actix, axum, warp, gotham, ruille
- stackskipton 2y agoAs SRE, I got interested in https://levkk.github.io/rwf/migrating-from-python/ 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)
- biorach 2y agoI imagine the author assumed a technical audience wouldn't need to be told of the necessity of a reverse proxy in front of the wsgi server
- drcongo 2y agoAs a Python dev, I imagined the same.
- stackskipton 2y agoAs SRE, you assume 100% wrong. Devs totally need to be told "Please don't do this in production." They will ignore you but hey, you might reach a few.
- levkk 2y agoI thought the same thing, but this allows you to test your changes locally as an application engineer, without the back and forth. This goes back to the good old monolith vs. microservices debate. Writing a stable WSGI server is possible, and not very hard with a bit of attention to detail, e.g. thread counts, vacuum (just like good old php-fpm, restart every n requests...), etc. Basically if you implement most options uwsgi has, you're on the right path. It's on the roadmap to make Rwf comparable to running Gunicorn.
- stackskipton 2y agoSure, but Gunicorn doesn't try and run Node. I totally get benefit for development; I was just worried about someone YOLOing this into production.
- deleted 2y ago
- fHr 2y agoNice 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.
- drcongo 2y agoOooh, mind sharing what you ditched web pack in favour of?
- unjkyivbnp 2y agoBased! 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!
- levkk 2y agoThank you! I tried to use standard async traits, but they don't support dynamic dispatch [1] which Rwf uses extensively. I'll be adding opentelemetry tags to functions (from the `tracing` crate). jemalloc can be added to the binary apps that use Rwf, we don't need to add it as a dep to the lib. Cheers! [1] https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#should-i-still-use-the-async_trait-macro https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-trait...
- sedatk 2y ago> use jemalloc for linux targets Why is that? Or, why isn't it required for other targets?
- levkk 2y agojemalloc (as opposed to GNU libc and LLVM) sometimes performs better. [1] [1] https://jemalloc.net/ https://jemalloc.net/
- deleted 2y ago[deleted]
- donq1xote1 2y agoI love rust!! This is so cool and I'm a beginner and I'm not sure if I can utilize this framework or not.
- levkk 2y agoYou definitely can. I remember learning Django and Rails as a beginner, it wasn't straight forward. New things are hard until they are not new. Good luck!
- wormlord 2y agoCool! 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!
- jakswa 2y agoLately I've been following https://loco.rs/ 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.
- deleted 2y ago[deleted]
- Guthur 2y ago```I think Rust makes a great prototyping and deploy straight to production language.``` How?
- jamiedumont 2y agoI'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!
- factormeta 2y agoWhat about Actix? There were some discussion on HN a while back related to Actix vs Axum if I recall that.
- selfmodruntime 2y agoI would love it if you could link that
- jcmontx 2y agoDo you plan on adding CRUD generators? That was the killer feature of MVC frameworks
- levkk 2y agoIt's there but the docs aren't written yet. See the REST example in the repo. I'll have some docs for that soon.
- robert_foss 2y ago@levkk How do you thing it compares to loco.rs, I'd like to understand the differences.
- stuaxo 2y agoSounds 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.
- dethos 2y agoAwesome, 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.
- lopatin 2y ago> 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?
- xpe 2y ago“Wild application ideas” and memory safety are orthogonal.
- Arch-TK 2y agoSurely it has a WSGI client not a server.
- imiric 2y agoAfter 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!
- qudat 2y agoAgreed on all fronts. Go has nailed the stdlib and every other language is in its shadow
- t-writescode 2y agoThis is a major component of what drew me to love C# so much for a while. It's also one of those Perfect StdLib(tm) languages. Many of the components do need to be downloaded through nuget; but they are a part of the stdlib!
- celdon25 2y agoWould it be a fair comparison? C# didn't have good support for JSON in the standard libraries for almost 20 years[1]. ADO.NET seemed like a failure to me as well, but maybe I just didn't understand it. The System.Drawing namespace at least as of .NET Framework 4.5 required virtually all of its operations to be done through a System.Drawing.Bitmap, which meant that no matter how your image data was represented, it needed to get rasterized. This wasn't a big deal for most desktop/local use cases, but it's very inefficient, so if you had any servers relying on this, and had a reasonably decent amount of traffic to those servers, you could be getting CPU usages way too high. As an example, I remember one time we were hosting 30 kb TIFF images (high res, 1 bit per pixel) for download, and generating the thumbnails was done in real time, which caused literally gigabytes in memory churn per request due to the rasterizations... IIRC I fixed it by using emscripten (this was 2015-2016) to do resizing and rendering in the frontend with a small C module using LibTIFF, then the server only needed to send the 30 kb files as is. Unfortunately I've had a hard time finding people to work with these days that give me that kind of room to execute. Does Go's standard library have these rough edges or is it actually pain-free? I'm on the fence about whether I should learn Go or Rust while I am on a short employment break. 1. https://github.com/dotnet/runtime/issues/27761 https://github.com/dotnet/runtime/issues/27761
- ConanRus 2y ago[dead]
- benpacker 2y agoWhat happened with PostgresML?
- miffy900 2y agoHonestly, 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.
- PaulDavisThe1st 2y ago> 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.
- timkofu 2y agoThanks 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 https://news.ycombinator.com/item?id=41760421
- levkk 2y agoYou got it. I will setup a GH action to release to crates.io at the same time. Cheers!
- metadat 2y agoAnother related submission from today: Ryde: A Rust Web Framework - https://github.com/swlkr/ryde https://github.com/swlkr/ryde (October 2024, 5 comments)
- Woshiwuja 2y ago[dead]
- DeathArrow 2y agoI'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.
- xwowsersx 2y agoYep, totally get where you're coming from. Many people, myself included, have had a similar experience starting out. To push through the learning curve, you need a strong motivation--whether it's because you have to use the language, you're drawn to the benefits of the type system and safety features, or something else specific to you. If you don't have that kind of motivation, it's totally fine. I didn't at first either, which is why my early attempts to learn the language didn't go far. Like many others, I found that it does take longer to get things done in Rust compared to languages like Java or Python. There's just more upfront thinking required. That's valuable in certain situations, but if you're not clear on why you'd make that tradeoff, there's no strong reason to keep going.
- chubs 2y agoCongrats! 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!
- levkk 2y agoThanks! Rust macros are typed, so the language server should be able to give good suggestions. They are also optional, and you can always use the code they generate directly. In most cases, it won't be too verbose either.
- throwaway313373 2y agoI 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#restcontroller https://github.com/levkk/rwf/tree/main/examples/rest#restcon...
- levkk 2y agoInteresting. I should reread the REST spec. I put not implemented as more of a tip to the developer to implement this method at their earliest convenience.
- mdaniel 2y ago> I don't think that not implemented method should return 5xx, because it is pointless to retry it. Pedantically, that's not true - it can be unimplemented at T0 and then a deploy happens and it will be implemented at T1. You are likely thinking of retries within the milliseconds timeframe, but even that could be true in a race-condition-esque situation where a redeploy was happening and the request just got unlucky In the context of this thread, not allowed is quite different from "happens to not be present." I think of the distinction like 404 versus 410 Gone <https://http.cat/status/410 https://http.cat/status/410> in a temporal state
- lord-squirrel 2y agoThis looks very cool!