Is it possible to add another section to the learning rust section (http://doc.rust-lang.org/book/learn-rust.html) on how to build a simple web app for experienced web developers? I would imagine this would form a sizable chunk of people trying their hands at rust.
Or maybe if there are already well known blogs/tutorials that address this, please let me know.
If you are coming from a J2EE/Jetty background then you might want to look at hyper which gives you the start of an “embedded” HTTP server. It doesn’t support things like session handling (yet?), it really only gives you a way of accepting HTTP requests from a web client and responding with the appropriate data.
I don’t know of anything, nor have I looked for, any packages with a more PHP/Python style of web programming, where the HTTP server calls into a back end program which executes the “page” on the fly to generate the response.
Not sure that would work well, since the rust compiler is not looking for speed in compilation but speed in your programs execution. You would probably have to create all the rust files for your pages, compile it into a single program, then have the HTTP server call that program. Which might be a fun library to create, but might piss of the developers because changing a page would involve a recompile, which is one of the nice things PHP/Python avoid. But the end result should be fast since it’s all native code…
Rust isn’t really made to be compiled on the fly. You could always combine it with a dynamic language, but then we are sort of back to what we had. One major advantage of a pre-compiled server, besides possibly being faster, is that it’s much harder to inject new code (close to impossible).
There are, by the way, some more libraries with varying levels of abstraction. This repo should have a fairly up-to-date list, and I see that there are a bunch of blog links there, too.
I think it’s also important that hyper itself is more of a low-level thing that other frameworks build on top of. Iron and Nickel are the two I see the most, there’s also https://crates.io/crates/rustful/
Yeah, the ecosystem isn’t as mature as in the default languages. It’s close enough to get things done, but you don’t have to look far to find areas where it can be improved. One big thing is the lack of asynchronous IO.
It would be interesting to hear what parts you found were especially lacking.
Here’s a list of some of the problems I encountered:
I’m on Windows, and the pre-built binaries of OpenSSL are incompatible with what the openssl-sys crate expects. I had to use a virtual machine with linux in order to work on the website. Maybe this has been fixed by now, I haven’t tried the past few weeks. Even if this has been fixed, it would be much nicer to have a wrapper around either OpenSSL or the encryption utilities provided by Windows, so that it just works.
There’s no crate to easily hash passwords encrypted with blowfish/crypt(3). Someone was kind enough to write me a gist. As you can see, it’s not really something a beginner could easily do. Note that I have yet to write the code that encodes passwords. For the moment it works with a hack.
Dependency hell with openssl-sys. At some point hyper and tiny-http were using openssl-sys version 0.6 and postgres-rs was using version 0.7. Since openssl-sys contains a links attribute, cargo refused to compile both postgres and tiny-http at the same time. I had to disable the ssl feature from tiny-http to make it work, and in production I’m using a nginx as a proxy to handle SSL just because of this problem. The fact that this is such a big problem and that nobody complained about this on reddit or IRC makes me think that not many people have tried Rust webdev. Also this is a problem that will often happen again in the future and that must be fixed ASAP.
Dependency hell with postgres, r2d2 and hyper. Would probably happen with iron as well, but I’m not using iron. This rule is not respected by these crates. For example if postgres depends on chrono 0.2 and you want to use chrono 0.3, well you can’t.
Postgres checks for the correct data types at runtime. I can’t blame it because it’s the only way to do, but the consequence is that you will get dozens of panics. You’re using a u32 instead of a i32? Panic. You’re using a DateTime instead of just a Date? Panic. The query returned null and you don’t use an Option? Panic. I had to read my schema over and over again to make sure that I was using the correct data types (especially for nulls).
SQL is also checked at runtime. This may seem obvious, but it would be nice to parse it at compile-time and check for typos.
Similarly, the templates of mustache-rs are “checked” at runtime too. If you make a typo, no compilation error. It would be nice to compile templates at compile-time with a plugin and generate structs that contain the variables needed by the template. But this would require plugins to be stable, which is probably not going to happen in the current decade.
Retrieving the result of a postgres query is really painful compared to other languages. I ended up writing some macros to help me, but this is also something a beginner will have trouble with.
catch_panic isn’t stable. For the moment my server spawns a thread for each received request just to be able to recover from panics. This is obviously not ideal. While we’re at it, there’s no way to get the stack trace of a panic, and getting the message can only be done in a semi-hacky way. For the moment if you want for example to get an email when a panic occurs, the only solution is to monitor the logs.
I had some requests dropping with hyper. I investigated a bit but couldn’t find why. Switched to tiny-http (a crate I wrote before hyper emerged) and they disappeared, except for a single occurrence.
I find the design of Iron and Nickel not adapted to Rust at all and far too difficult and annoying to work with. Plus dependency hell. I ended up writing my own monolithic framework. Over time I have given up trying to convince that my way was better. I’m just writing my own stuff in my corner and let people praise Iron and Nickel.
There’s only one crate to parse the multipart/form-data content-type (ie. file uploads from forms). But for some reason this crate depends on hyper, even though there’s no reason to, since it’s just about parsing data. Since I’m using tiny-http I’m reluctant to use it, as it would pull hyper as a whole in my dependencies graph. I don’t think the crate compiles anyway. This is yet another thing that I’ll probably end up writing myself.
Compilation times. Waiting 30 seconds between a change in the code and the moment you can try it is a bit too long. This wouldn’t be a problem if everything was checked at compile time, but see above the problem with runtime checks.
Maybe there are others, but this is what I can remember.
I completely understand, if you feel that trying to convince people about this is a waste of time. But for what it’s worth, you got me to think about this topic. I think that you’re right about Iron and Nickel and I am currently trying an alternative approach that is heavily inspired by what you have written on the topic.
Thank you for doing your thing and for writing about it. At the very least, it inspired me!
Thank you for writing this up. I recognize some of those problems. I have been lightly touched by the dependency problem, when Hyper decided to update one of their non-reexported dependencies without warning. This broke one of my examples, and I have ever since considered any change of dependency version a breaking change. At least as long as they are pre-1.0. I have even considered locking them down completely.
I have also bumped into the OpenSSL problems when testing Rustful on Windows. It’s surprisingly hard to make it work smoothly. It feels like OpenSSL isn’t even remotely targeted for Windows. I have silently accepted it until now (partly because I’m mainly a Linux user), but it’s seriously starting to annoy me.
This is both surprising and worrying. I wonder why this happens.
I think the reason for Hyper dependency is that it uses the MIME type to validate the request. It should be possible to make it independent, as far as I know.
I haven’t seen this before. Interesting.
I can understand your frustration when it feels like the compiler isn’t used to its full potential.
I can only answer for Rustful when it comes to this, and the use of panics. One of my (if not the) main priority is usability, and one way to achieve this is to never panic if it can be avoided. There are some panic points, but those should only triggered by bugs or misuse. I’m also reluctant to do runtime checks, because I see the compiler errors as such a great resource. I admit that there are some dynamic parts (the global storage in particular), but I don’t want them to be mandatory. I don’t see forced panics and unnecessary runtime checks as good usability. Especially not in Rust.
I’m not saying that Rustful is better than the alternatives. I just felt like sharing some of my views and goals regarding the way it works.
This library is probably not something that I’m going to maintain. I’m mainly into gamedev after all.
If this was someone else’s library I’d contribute to it (like I did for tiny-http which I transferred to @frewsxcv), but not do everything myself.