Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Rocket – Web Framework for Rust (rocket.rs)
484 points by sbenitez on Dec 23, 2016 | hide | past | web | favorite | 114 comments

I am not a web development guy, so this question might seem ridiculous: To me, it always seems that there are a lot of hazards in any web development project, security-wise: A number of attacks, be it injections, XSS, etc. When seeing a new web development framework, I always ask myself: Are the basic security concerns known today addressed? How can I make sure that choosing cool web framework in language X doesn't lead me to an unsafe webapp? Perhaps somebody with more knowledge in web development could chime in here and help me; I would really appreciate that.

I wrote a long reply, but ended up erasing it and I'll just say that many of these vulnerabilities are due to the programmer using one type (i.e. string) to represent all kinds of data that might be malicious and unsanitized, and then losing track of whether a piece of data is safe for use (e.g. to be sent to DB) or not.

I recommend checking out the Yesod web framework [0], which leverages Haskell's strong type system to provide type-safety and a whole range of nice guarantees, including preventing vulnerabilities like the ones you mentioned.

Spock [1] is another cool web framework also written in Haskell that looks quite promising.

[0]: http://www.yesodweb.com/page/about

[1]: https://www.spock.li

Yesod doesn't prevent all of them. You can use "javascript:" to still do XSS, last time I checked. This is because that kind of content is valid in HTML... but maybe not what you wanted to happen

Content Security Policy headers can be used to prevent XSS attacks. Caveats are, user must be using a modern browser, and you have to move all inline scripts out to a .js file. Read more here: http://content-security-policy.com/

I don't see why javascript: is fundamentally different than other XSS vectors

because for other types of injections Yesod WILL actually properly encode <script> tags and make them &lt;script&gt; which will prevent SOME XSS exploits

but it doesn't prevent all of them

This is not true, at least not anymore.

Yesod uses xss-sanitize [0], and their sanitize function does indeed prevent "javascript:" attempts. They even have a test case for it [1].

Playing around with it in the REPL:

  Prelude Text.HTML.SanitizeXSS Data.Text> sanitize $ pack "<IMG SRC=javascript:alert('XSS')>"
  Prelude Text.HTML.SanitizeXSS Data.Text> sanitize $ pack "<IMG SRC=\"javascript:alert('XSS')\">"
  Prelude Text.HTML.SanitizeXSS Data.Text> sanitize $ pack "<IMG SRC=fine>"
  "<img src=\"fine\">"
  Prelude Text.HTML.SanitizeXSS Data.Text> sanitize $ pack "<IMG SRC=\"this is ok too\">"
  "<img src=\"this is ok too\">"
[0]: https://hackage.haskell.org/package/xss-sanitize

[1]: https://github.com/yesodweb/haskell-xss-sanitize/blob/9a9101...

This is actually the million dollar question, not remotely ridiculous. A lot of web frameworks are built with ease of use, productivity, and "fun" for developers in mind, but neglect security at the framework level, instead leaving security to be reimplemented by the devs on every new project.

But the whole point of a framework is to encapsulate all the things that you have to implement for every new web project, so you don't have to keep redoing that every time, and can instead focus dev time on new features and unique elements of each individual site. Securing against common vulnerabilities should be part of that.

There are a few frameworks that get this right, Lift (https://liftweb.net/) being the best I know of, designed to eliminate most of the OWASP Top 10 Vulns (https://www.ibm.com/developerworks/library/se-owasptop10/ind...) using Scala's strong type system and a virtual diff architecture similar to now-in-vogue Javascript frameworks like React. Haskell's Yesod framework is, as mentioned above, another good one in this respect.

Thank you; these answers have been most insightful! I learned quite a lot from browsing the links.

I am writing "answers", plural, because although I post this as an answer to SkyMarshals text, I also mean the replies by aban, peller, and petilon.

The canonical resource I'm aware of is the OWASP project.[0-3] Basically though, always escape user-supplied data (and make sure you're correctly escaping it for the contexts of where it ends up[4]), don't roll your own crypto/authentication, and stick to using battle-tested libraries. (If security matters that much to your app, stick to "boring established framework X" and let other people choose "cool new framework Y".)

[0] https://www.owasp.org/index.php/Category:Popular

[1] https://www.owasp.org/index.php/SQL_Injection_Prevention_Che...

[2] https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_P...

[3] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(...

[4] A good framework, used correctly, should take care of most (all?) escaping for you. For SQL injection, it's the ORM's job. For XSS, anything using a virtual DOM should escape stuff for you (I know React does). CSRF is more to do with session management, which is where using battle-tested auth code comes into play.

Virtual DOM doesn't really have anything to do with preventing XSS. It's done in angular 1 as well.

Really, it's about taint checking [1]. Distrust all sources of content by default that might have seen user input (or that you know have seen user input), and require explicit trust declarations from the developers to remove taints.

When you're about to use the data (e.g. appending to the DOM), you simply check for tainted data and escape is for the context you're in. Most times in the browser, that just means escaping content that might be valid HTML, but there are probably other contexts that require escaping as well.


Ah, thanks for the clarification! Today I learned :)

There's also that if you're using React (vue, Angular, et al) with a JSON API (as is usually the case) you've also got CSRF forgery dealt with somewhat automatically as well.

For once, modern implementations are actually really helping security.

In this vein, one thing I'm not seeing (although I haven't finished reading the "book" yet) is built-in CSRF protection.

While not difficult to implement correctly yourself, I've found that applications written on frameworks that don't include this in the box tend to be applications vulnerable to CSRF.

Excellent! I'm glad to see that this is on the roadmap :)

Frameworks vary in how idiot proof they are in terms of security. For example web2py has everything set fairly secure out of the box and you have to go out of your way to break it. Others may require a bit more sense from the developer.

It's a fair question, considering things like Cross Site Scripting (XSS) and Cross Site Request Forgery (CSRF) -- especially the latter -- can be mitigated by using a well constructed and tested framework.

Syntax is amazing! Hope (so much) to see it possible on beta soon. Maybe for somebody it's not a new thing, but for me this:

  struct Message {
     contents: String,
  #[put("/<id>", data = "<message>")]
  fn update(id: ID, message: JSON<Message>)
where message is auto-decoded - it's awesome!

Since you mentioned "for somebody it's not a new thing": this looks a lot like Flask, if you're into Python (except for the type safety); I'm sure there's a Ruby equivalent. It looks a lot like Jersey on the JVM (for Scala, Java, etc).

This pattern is really nice for web frameworks. I'm super excited to see it for Rust! To me, this signals that we're getting pretty high up there on the early-adoption curve.

Sorry but I cannot agree. I work on the JVM and this pattern is great for "hello world" webapps but breaks down pretty quickly. When large parts of your logic like metrics, security and routing is being done with metaprogramming you're really doing yourself a disservice.

If you don't like routing being done with metaprogramming, you can manually create routes yourself similar to this example[0]. I think the author is trying to show appealing APIs.

[0] - https://github.com/SergioBenitez/Rocket/blob/master/examples...

Thank you. Actually, that underlying API looks great. I would prefer it any day of the week.

I've worked a lot with this pattern in Python (Flask), Java and Scala. I have found it a little inconvenient beyond the simple hello world app when dealing with Flask, but I haven't encountered this problem with Java/Scala. To date, I've worked on probably 4-5 separate applications using this pattern and it's worked quite well. I have also used Spring 4 on the JVM, which ... feels more flexible, but also has a lot of cognitive overhead, and so I'm not crazy about it. I believe Spring Boot follows closely after Jersey, most likely as a result of the pattern's popularity.

In my experience, it is pretty straightforward to build your resources (as Jersey calls them) into various classes without any issue, even for applications with many API endpoints.

As for metrics, security and routing, most of these are canonically managed using annotations in Java. In Spring, application context XML configurations are used, but they are very big and not close to their actual implementations, which makes them get out of control quickly (and inconvenient when they aren't out of control). It feels like losing either way.

I'm a big fan of Coda Hale's work on Dropwizard, which uses metrics, security and routing through annotations, and it works very well for large scale production applications. I use these techniques at scale at Bazaarvoice with great success.

To be fair, I won't go so far as to claim the pattern is imperfect. It's just the best pattern I've used for web services to date, even at scale.

I would love for you to expound more on your own experiences in more detail!

edit: clarification on where I've used the pattern

I've worked on everything you mention and more, and I find the simplicity of say node.js or SparkJava very refreshing when coming from metaprogramming frameworks. Once you go metaprogramming everything is suddenly metaprogramming. Data serialization is metaprogramming. Middleware is metaprogramming. Adding your own plugins to the framework becomes metaprogramming.

Also, because the framework wants to create your classes you cannot simply send in the objects dependencies into the constructor anymore. You find yourself in need of a DI framework instantiating your classes. And suddenly the data dependencies of your app become very vague. Adapters get registered based on the presence of JARs and/or classes in directories which are scanned in runtime.

You have reinvented the work of the compiler and the language, and what do you gain? A big mess where you no longer have programmatic control. I cannot easily start parts of my application for testing, I have to rely on Spring or Jersey having some sort of metaprogramming magic triggered by some magic annotation supplied by a JUnit<->Spring integration module. Suddenly modules like JUnit and Spring aren't combinable without metaprogramming. You see this trend spreading like wildfire: "Is your lib Spring compatible?". We should instead be asking ourself why the heck unrelated libs have to be compatible with one another. They are supposed to be orthogonal, that's the point! To see an example of how ridicilous this can get, have a look here: http://stackoverflow.com/questions/35957287/cucumber-testng-...

I wouldn't go as far as saying that frameworks like Spring or Jersey are unworkable. But I believe you could acheive the same level of service a LOT easier if you wouldn't go metaprogramming crazy. Just consider the amount of time wasted trying to figure out why something isn't wired correctly, why some plugin is loaded, why your component isn't picked up, why some property isn't resolved etc. With normal programming, you fire up the debugger and step through the code. Solved in 5 min. With metaprogramming, it's a struggle on a whole different level.

Thanks for clarifying. I agree with you, mostly.

This is exactly the reason why I refuse to use Lombok. It literally mutates your bytecode! That's a disaster waiting to happen, and a potential debugging nightmare.

I think that there is a fair balance where metaprogramming has great utility. For example, I'm a huge proponent of Guice. And yes, sometimes it makes debugging issues a little more complicated. OTOH, without it, there's a lot of boilerplate. Admittedly, DI in Java is a workaround for an inherent Java problem (boilerplate). Maybe it wouldn't be so useful in other languages/ecosystems. I have written services both with and without DI, and prefer it, and haven't had significant issues debugging or managing it. But it must remain scoped.

As for library compatibility issues, that is more of a byproduct of dynamically linked libraries than metaprogramming. If you're writing in a JVM language, you're kind of stuck with this (OK, you could shade your library and all its dependencies to get away from it, if you want to deal with the bloat / impact to the JIT'er).

Having said all that, your statements are arguing against metaprogramming, and I'm not really arguing for or against metaprogramming in my original comment. Simply, I think the pattern of defining HTTP resources in the aforementioned way is very intuitive from a software development perspective. If it can be done without metaprogramming, then great. But the presence of metaprogramming doesn't, in my mind, preclude the effectiveness of the pattern.

Ok, I hear you. I agree somewhat, but not totally :) To me, the most important aspect of programming is to retain full control. I for instance want to be able to register my HTTP endpoints based on some data read from a file. I want to be able to start my app in server mode and run requests against it in any way I want during testing. What many of these frameworks do is to remove this power.

Bytecode modification is not too bad IMO, as long as it's within reason. I use a notnull annotation weaver to add notnull assertions. Not Lombok, that's too much for me as well. Should be another language really, like Kotlin.

Metaprogramming does have utility. But it has a tendency to go overboard. I actually find Jersey to be a good example of a nice and clean API for defining resources. I recently tried to integrate it into a small app where we do all the wiring manually for clarity. The problem is that it's hard to stay in programmatic control. You define a resource. You realize you need a Service in your resource. You realize that the only way of getting it into your object is to inject it with the JAX-RS annotations. And so suddenly your service has to be a JAX-RS @Singleton service. You have to make your whole app JAX-RS compatible. The framework takes control. This is really bad IMO. A library which requires control over your program.

This is not an intrinsic problem of metaprogramming, but IMO it's a big problem of Java as it stands today. We need to give up on frameworks, make sure that all libraries are combinable and that they don't take control of your app. Doing so would make everything a lot better.

I wish I could just do:

new Jersey(config).addRoutesIn(new HelloWorldResource(new MyBackendService(dbDriver))).addSerializer(new JsonSerializer()).start();

This would then utilize some reflection when routing requests, but not take over my entire app.

Regarding the libraries, my point was not that you get conflicting classes (DLL hell sort of thing), but that we're building multiple products which want to take over the world. JUnit wants to be in control, and so does Spring. So when you try to combine them, you end up with a problem. Can you start Spring programmatically from a JUnit test? Well, not really. You can, but it's very involved. So they want to provide you with a Spring-JUnit integration. This is a really bad idea, since every linear combination of libs has to get an integration, like the link I included in my post. If all these libraries just tried to stay out of the way of the programmer and just provide a programmatic API, there would be no need for such integrations.

To jump into a really interesting discussion: I totally get what the both of you are saying, but I think that the real problem are poor abstractions. In some sense SQL is code generation since it's a declarative way of describing what you want which the query planner figures out how to realize. At least to me, it's rarely a source of frustration. Why? Because it's a sound, proven abstraction based on a very solid foundation. In the frameworks that figure in this discussion, there's no such thing, and all the abstractions I've seen are leaky under some scenario.

That makes me prefer minimal, magic-free tools, because even if it's sometimes a source of extra effort, at least I won't have to spend time fighting the framework. The fear of boilerplate seems strange to me. I'd much rather spend the extra ten seconds of adding a route manually through a line of code than no time at all if it spares me having to spend an hour figuring out why my ContextProvider isn't being registered by the classpath scanner.

I had to think about your comment. Yes, SQL is a sort of code generation and you could argue that annotating classes also is code generation. But my main pain point is that most annotation frameworks are frameworks and assume that they are in control: that they start the app and that the application programmer must write their whole app according to the rules of the framework. That's like if a SQL client lib would assume that the whole app was written in SQL.

Your post totally resonated with me, particularly how once you go metaprogramming everything is suddenly metaprogramming. I work at a Spring shop and we joke about how we should just be called Senior Java Annotators. I find it ironic that Spring does all this machinery in order to instantiate your application, yet often you end up needed to use the Order http://docs.spring.io/spring/docs/current/javadoc-api/org/sp... annotation anyway to get things to wire up in the right way...at which point, it is kind of like, what even is the point of using Spring then? We waste tons of time figuring out what is getting configured, injected, instantiated, etc. to the point where I'd rather just define everything myself in the order I need it, so I know exactly what I'm getting and why. I miss normal programming, normal debugging, and normal application initialization.

And then there is the problem of CGLib wrapping e.g. for @Transactional and other annotations. Of course, it only happens for other services calling into your wrapped service. If you call your own methods from within the service, you're hitting just the service instance, not the wrapped instance, which causes all sorts of headaches. Yet people still take this disaster further with Lombok/bytecode manipulation and aspects.

http://sparkjava.com/ looks very appealing; it looks very much like http://koajs.com/ which I really respect.

Hey! A colleague who also sees the light! I've been pushing for more programmatic control in our apps due to the same problems you mention. I would actually consider myself one of the most versed in Spring at our shop. But while I see so many problems, many devs only see "the beauty of the minimal code". I wish I could understand what is blindsiding them from all the problems we have.

The latest incarnation of this problem is Spring Boot. It does some really far out stuff to your app, like making m separate metrics for each unique url of your webapp. That goes south pretty quickly. Not to mention how much longer the app takes to start, how much slower it is compared to coding the same functionality manually (x4), how much trouble people have getting the right mental model of how the app works (with instrumented transaction boundaries and stuff that you mention), how hard it is to debug (why did this endpoint return 404?) etc.

We did some POCs with vert.x and spark, and all of a sudden you see what type of overcomplicated mess we have been creating for ourselves.

I disagree. It's great syntax for controllers - place where you should read request data. Services is another story , but you will always have place where you read initial request data.

Edit: should preface this by saying the framework looks really impressive. I've been looking for a Rust web framework to settle on and this is the most appealing.

It's funny to note how much something small like this matters. It's syntax sugar and presentation, but the difference a comment like this has at the top of an HN post vs an ambiguous but detailed discussion about feature x...massive in effect.

It doesn't seem to be the case, but the entire framework under that could be bad yet it's caught mindshare on the basis of routing syntax (one of the smallest worries in a production web application). Wonder how many frameworks have failed just on the basis of not making a similar decisive first impression?

Syntax matters?

We're in the process of addressing discoverability of the crates.io ecosystem, which led to this RFC: https://github.com/rust-lang/rfcs/pull/1824

A quote from it:

> By far, the most common attribute people said they considered in the survey was whether a crate had good documentation. Frequently mentioned when discussing documentation was the desire to quickly find an example of how to use the crate.

Open source projects, in a sense, are like startups: if you want to acquire users, your users have to be able to understand the product! A deeply impressive technical project is, well, impressive, but if nobody can figure out how to use it, it's not going to see nearly as much uptake as a technology that's got a clear and easy way to use it.

There's secondary effects too: a project with a slick website like this makes people take it more seriously. It's less likely that someone who put this much effort in is just going to drop it immediately, though of course, that's not an absolute rule.

TL;DR: developers are users too. Developer marketing matters!

Can I just say, I cannot applaud you enough (nor other contributors to rust) for how much you care about developer opinions and ease of their introduction to the language and subsequent use! I freaking love you guys.

API (and modern web servers are API only) should:

1) handle route (read data, transform, prepare other resources, check access rights)

2) generate response with reading/writing to db.

First step is not so primitive. Reading request data is often boilerplate-rich code, so syntax which can remove tons of boilerplate is very welcomed.

Personally I don't like domain-specific sugared syntax. I prefer clarity above all, especially since I hope to spend the least possible amount of time in the networking domain, and this means I'd otherwise have to relearn the syntax whenever I have to dig into the code again.

When digging into new projects I always find that there's going to be cognitive overhead because of certain abstractions.

    let always_forward = Route::ranked(1, Get, "/", forward);
this is a normal function call, but what does it mean? Is that really better than special syntax that desugars to this code?

Yes, because function calls are much easier to trace down than special syntax.

Syntax is why sinatra and express got bit.

Just add a callback for your route and off you go.

What does "got bit" mean?

he means got big ;)

lol, yes sorry. got bit sounds like I meant the opposite.

Thanks. That does make more sense. :)

Indeed way cleaner than Iron in terms of parsing query (int) arguments and JSON post data (BodyParser).

One of my influences, Armin Ronacher, has been doing a lot of Rust work lately, so I've been thinking about looking at it more closely since I appreciate his Python tastes.

Is Rust simple and elegant in the sense that Python is? I've also heard it's for systems programming, which makes me think of C and has kept me away from it. I like how I can bang out scripts quickly in Python. Is the same true of Rust?

edit: found this http://lucumr.pocoo.org/2015/5/27/rust-for-pythonistas/

I use Rust a lot for my generic scripting around the office. Small tasks like copy a few thousands files, selectively re-naming them based on a group of regexes.

The Regex crate (which I think is being merged with std) uses the same syntax as Python's regexes.

The Path/PathBuf type in std makes manipulating paths easy (and type safe). No more slicing notation/regexes to find where extensions start. Also it handles unix/windows / vs \ for you.

Python DuckTyping slightly drives me insane. What interfaces are/aren't typed feels like Russian roulete. Nothing like the 4000th processed file crashing your script

The real win is compatibility. If you avoid unsafe you don't need to think to port to Linux/MacOS/Windows.

Lastly it's a binary. So to share with a coworker, just copy it. No module management.

> (which I think is being merged with std)

It's on that path, but it's unclear if and when a literal merge into std will happen. Right now, the design of 1.0.0 has been accepted, and once that lands and is released, it will move from "the nursery" to the regualr rust-lang org. From there it could go into std, or it may just stay there forever.

regex has some dependencies, though.

aho-corasick, memchr, thread_local, simd, utf8-ranges

That functionality would have to be in std.

Regex in std would sure be nice, though.

Can be in std without being exposed. libc does this IIRC; the stdlib depends on libc but doesn't expose it.

Right, so this would be one of the questions with moving it into the actual distribution. All of that would have to be replicated in-tree and stabilized separately...

> The Regex crate (which I think is being merged with std)

To add to what Steve said: there are currently no plans to export regex from std.

> I've also heard it's for systems programming, which makes me think of C and has kept me away from it.

One of its major goals is making systems programming more accessible. So you shouldn't dismiss it because "systems programming = C", it's trying to change that! :)

That's not to say it won't involve learning some systemsy concepts. But it won't be as scary as C.

You can't necessarily bang out scripts quickly. A type system tends to make this task verbose. However, larger applications benefit a lot from that type system.

We've often had feedback from Python/JS shops using Rust that learning Rust had the side effect of teaching them systems programming. I think that's pretty awesome.

I guess I'm contrasting Python with my Java experience so far as banging out prototypes quickly.

In Java, I don't think the type system gets in the way so much as its classpath. It's been a long time since I've done Java, but you'd have to get your jars in order and write an ant or maven script to do the compile/run steps (or at least a bash script).

I like that with Python I can just do pip install whatever and begin using the module immediately in my main method. In Java, It's not standard practice to copy jars into the system classpath IIRC, so you'd have to copy them around every time you want to do something new.

I need to investigate Rust's command line interface. Obviously, the more it can get close to

python main.py


javac -cp foo/Bar.jar:baz/Quux.jar Main.java; java --classpath foo/Bar.jar:baz/Quux.jar Main

the better it will be for this use case I mention.

Thanks to both of you for responding!

Calling `cargo run` has made it easier for me to treat it as a scripting language since it combines the build and run steps in a single command. Good luck with it!

I believe Rust's package manager, Cargo, is quite similar to pip in functionality. I haven't used it myself, so I could be wrong.

In some ways. It's also got the features of https://github.com/pypa/pipfile

It is way better than pip on the sense it works everytime. pip is not painless. It is close but miss by little. Got to hate it because of numpy.

> We've often had feedback from Python/JS shops using Rust that learning Rust had the side effect of teaching them systems programming. I think that's pretty awesome.

I'm a self-taught developer who only practiced memory-safe languages before and I never dared trying C because of its reputation of being too difficult. Rust taught me a lot of things about system programming I never though I will learn one day.

A big thank you to the whole Rust team for that !

There's nothing that makes typed languages inherently more verbose; a Haskell script will tend to be substantially shorter than the equivalent Python.

Rust gives you much more control over how your program runs, but this necessarily means paying a price in expressiveness.

I didn't say typed languages are inherently more verbose. I said that a type system tends to make things more verbose (in some cases), e.g. having to bang out types in function signatures, etc. When writing small scripts you usually just write down what you want to happen, and it works. There's some extra mental/typing overhead in a typed language in many cases. For larger programs, this overhead isn't important since you get many other benefits, but for small scripts sometimes it can be problematic.

It's not a hard-and-fast rule. It's something that I've experienced when trying to write small scripts in all kinds of typed languages. I keep going back to Python.

For larger scripty things I've found typed languages to work just as well.

> but this necessarily means paying a price in expressiveness.

I don't think this is true. You can have higher level abstractions in Rust too.

Not type systems per se.

But lack of garbage collection and the need for lifetime annotations for references and memory management with Box, Rc, Cell, Mutex, etc, combined with the type definitions makes Rust a lot more verbose than any dynamic language or even statically typed languages with GC like Scala / Go.

That can't be avoided, but you have to be prepared. Rust code can be short and elegant, but it can also be tediously verbose.

>a Haskell script will tend to be substantially shorter than the equivalent Python.

someone offered a counter-example where a JSON parser had more lines of type definitions in Haskell than total lines of code in Python

I wouldn't be surprised if the Python solution were shorter than Haskell version that doesn't use lens.

If you link me the example maybe I can provide a Haskell version using lens.

I've been using rust to as a more performance-oriented tool alongside python. It _is_ a different tool: there are certain tasks (for an irl example: taking a Unicode data file, parsing its contents, transforming it in some way, and writing it to disk) where python works very well and Rust feels like overkill.

That said, Rust is very elegant for the work it is doing. Rust iterators and iterator adapters are a powerful and clean way of manipulating collections, and the `match` syntax is an elegant way of handling errors and Option types.

Rust isn't a scripting language in terms of its strengths, but it isn't far away in terms of how pleasant it is to read and write. I would definitely suggest taking a look at it next time you run into performance constraints in python: it's easy to create python-native modules & interfaces with tools like rust-cpython (https://github.com/dgrunwald/rust-cpython).

Sounds like http://lucumr.pocoo.org/2015/5/27/rust-for-pythonistas/ is a thing you'll want to read. It's from right when 1.0 was released, so some things may have improved in the meantime, but given our backwards compatibility guarantees, nothing should be flat-out wrong.

And some more recent writing from him as well: https://blog.sentry.io/2016/10/19/fixing-python-performance-...

I started out as an assembly programmer and before Rust I was using C/C++ for systems and embedded, Typescript for browser frontend, and Python for everything else. I still use Typescript for the browser and Python for Jupyter (prototyping and ML) but Rust has largely replaced C/C++/Python for most of my work. Elegance and simplicity mean different things to different people but I'll give it a shot.

Unfortunately, Rust doesn't have an interpreter so it's not as great as a general scripting language but realistically, there's only a few extra lines you have to learn (extern crate and fn main() {...} mostly) along with the compilation step. Imports work more or less the same in both languages but I find Cargo to be far superior to pip as a package manager. You won't run into dependency hell very often and deploying a Rust project is very easy.

As far as writing Rust, it has static typing so if you want to carry over your programming style from Python it will take some getting used to. The extra type information in definitions can be annoying at first (especially with generics and iterators) but overall provide an intangible productivity boost with type inference filling in the gap. Rust objects are basically pure data structures without inheritance so you have to get used to thinking in traits. That said, with conversion traits like Into/From and generics with trait bounds, I can write code as if it were a dynamic language with duck typing (once I've defined my types) with just a little extra boiler plate to tell the compiler the similarities between this duck and that duck. For example, you can write a function fn foo<T: ExampleTrait>(T bar) and call it with any argument that implements ExampleTrait or Into<T: ExampleTrait> for quasi duck typing.

Finally, I feel I'm far more productive in Rust than in Python, assuming I don't need any functionality in the Python stdlib not yet implemented as a crate. On average, Rust crates are slightly lower level than Python's libraries but I find that using them is no less ergonomic, albeit more verbose. Most of the time, if I haven't made a logic error, any Rust code I compile just works and i don't spend countless hours debugging silly errors like variable name typos or magic object changes. More importantly, in Rust, you can encode a significant fraction of your logic into the type system which will be enforced by the compiler. For example, in my STM32 motor controller, I encode physical units as types so I can't accidentally feed the motor a 1000 volts when I mean 1000 millivolts because the Into<ControlSignal> trait calculates the signal based on the input type.

I would definitely give Rust a shot but don't expect to be as proficient in Rust as quickly as Python. The community is younger (but no less helpful) and the ecosystem is still catching up. Most importantly, don't let Rust's status as a systems programming language deter you. It is a low level language but is a modern language that was designed from the ground up by very smart people who incorporated the lessons of the past. Rust's zero cost abstractions, compiler plugins, and tooling have started to bridge the ergonomics gap between high level scripting languages and system development.

Thanks I look forward to checking it out.

It really dedends on what you are doing, but if you are building small scripts that aren't necessarily reliant on specific libraries, Nim is probably better than Rust.

This demonstrates the brilliance of Rust's syntax extensions. Not only is the code more readable and ergonomic, but also type safe.

Errors or mismatches in implementations are caught at compile time, saving minutes (or potentially hours or days) in frustrating debugging.

Nice work! This looks fantastic.

> This demonstrates the brilliance of Rust's syntax extensions.

Sadly this functionality currently requires nightly or using a code generating build script via syntex :(

(Rocket currently only works with nightly, but someone could pretty easily add a syntex port since the APIs are the same)

With macros 1.1, some of this functionality is available on stable, but not the functionality needed by this. I don't know if we plan a "macros 1.2" that stabilizes tokentree expansion for all decorators (not just type item decorators). ("Macros 2.0" is the final polished version of Rust procedural and regular macros, for which there are concrete plans but it will take time to get to)

For those not watching the compiler development traffic, macros 1.1 (which will enable things like #[derive(FromForm))]) could land in stable as soon as 6 weeks from now. We haven't really started thinking about a "macros 1.2" yet, so syntex will still have some use.

If you want to know more about our glorious macros 1.1 future, David Tolnay just have a great meetup talk all about this a few weeks ago:


The plan is for macros 1.1 to land in the next release, I wrote about it yesterday: https://news.ycombinator.com/item?id=13239774

Are dynamic params enforced at compile time? I.e. will the compiler ensure that the route "/<id>" has a matching id parameter?

Yes! Here's what happens when you don't do the right thing:

  error: 'id' is declared as an argument...
   --> src/main.rs:8:9
  8 | #[get("/<id>")]
    |         ^^^^

  error: ...but isn't in the function signature.
    --> src/main.rs:9:1
  9  |   fn hello() -> &'static str {
     |  _^ starting here...
  10 | |     "Hello, world!"
  11 | | }
     | |_^ ...ending here

that is some truly incredible developer ux

The span for the “...but isn't in the function signature” should be just the `()` rather than the whole function.

Fantastic work! Taking full use of syntax extensions for code generation is a clear winner in terms of dealing with what would normally end up being a bunch of copy pasta code.

edit: see replies to my comment. I mistook the Hyper pull request being merged for being in the latest release, but it isn't.

Rocket uses Hyper for its HTTP server. So I checked to see if the Hyper HTTP server was really production-ready. Particularly, if it could handle async IO / solve the C10K problem[0]. It looks like Hyper implemented async IO[1], so it should be adequate for production use in this regard. This is great news for users of Rocket because it means you don't need a separate HTTP framework to run your web service, as you would with, say, Django + gunicorn.

Sure, it's a dependency, but in this case, having a production-ready HTTP server out of the box is really nice!

Having said that, is there any literature on Rocket/hyper for security? The production-ready HTTP server is great, but it also means it has to be prepared to deal with certain security issues, like listening on and handling file uploads. You could put HAproxy/nginx/whatever in front of it, but I think Rust has the potential to supply / manage all of this within one unit and simplify the stack / attack surface area.

[0]: http://www.kegel.com/c10k.html

[1]: https://github.com/hyperium/hyper/pull/778

Hyper is not yet async, the preliminary work in the PR you linked to is for a version which has not been pushed to crates.io and is not finished yet.

Hyper 0.9 is async. It does not use futures/tokio ecosystem so it's ergonomics are weak in places, particularly on the client side. I believe the tokio branch of hyper is basically complete and only waiting on tokio to release.

Being very excited about another Rust web framework, I've been trying to use this for the last few days. While the basics seem very interesting, there's a few large stumbling blocks ready for anyone who might want to "get serious" with it.

Documentation is very sparse. Indeed, the linked to page seems to be the primary documentation repository. This is particularly painful for a brand new project, because googling is wholly useless at this point (the only relevant results being the linked-to page). You can try to infer things from the API, but there's a lot that I would refer to as "hidden gotchas" which you'll only learn about through experimentation or by reading the source.

For example, consider the FromForm functionality. Does it decode url-encoded values? Turns out the answer is: maybe. If your struct defines the field as a String then the input will be url-decoded, but if you define the field as a str then it won't be. FromForm only works at all if the submission is of content-type 'application/x-www-form-urlencoded', failing entirely 'multipart/form-data' for example -- I have no idea how you're meant to go about parsing a multipart form besides doing it manually using just the raw post-data string as input. Also, good luck parsing anything with a checkbox (as their code example does) -- if the checkbox is checked, no problem, the field is populated with 'true'. But if the checkbox is left unchecked, then you get a parse failure because you're "missing" a field. There may be a way to work around this but if there is it isn't well documented and I haven't read through that part of the rocket source yet.

I didn't see it in the docs, but does there exist a concept similar to java's servlet filters. For instance to check apikeys globally, perform compression, input validation, etc. Really any common operation across multiple routes.

I suppose this an advance for those already using Rust but the core message on the front page doesn't speak to me as a non-Rust person.

FTA: Rocket is a web framework for Rust that makes it simple to write fast web applications without sacrificing flexibility or type safety. All with minimal code.

I'm at a total loss for why I really care about this major part of their message (type safety). If I have already switched to Rust then I care about type safety already and you don't need to sell me on Rust, you should focus on differentiating this web framework from the ones that came before it. But if I haven't switched to Rust then I am essentially unswayed by their messaging. I can't see why it's particularly important or different over other language/frameworks for web development.

Before learning Ruby I watched the Rails blog video sometime around version 0.14.3. Immediately you could the value of the framework and the ease of a language I was unfamiliar with. The win I could see was productivity and it was enough for me and a lot of other people to learn Ruby. I don't see that with this framework or really anything in the Rust world.

What I think the author is trying to portray is that they achieved Ruby/Python level code (in terms of boilerplate and readability) while retaining the typesafety and performance that makes Rust attractive in the first place. That's a step up in every direction. This is, of course, tackling the notion that readers might associate strongly-typed web frameworks with verbosity and complexity, whereas Rocket is neither.

I think that's important to those both familiar with rust (who want a clean framework) and those who aren't (who want a safe language without sacrificing productivity).

> I'm at a total loss for why I really care about this major part of their message (type safety).

Honestly, you might not care about type safety. It depends a lot on the kinds of programs you write.

In general, a language with a good type system[1] brings several major advantages to the table:

1. If your program compiles, there's typically a 90% chance it will work correctly on the first try, even if you just changed hundreds of lines of code.

2. Big refactorings are much less stressful.

3. Emacs or Visual Studio Code (for example) can provide pop-up completions of names and methods.

4. Problems like mysterious nulls or data races can be prevented almost entirely at compile time.

One big downside is that it gets harder to do certain kinds of (runtime) metaprogramming and you need to use macros to get similar effects.

At this point, having worked professionally with Rust, I would recommend Rust to people who are really enthusiastic about the above benefits. But if you look at that list and say, "Meh, not worth it," then you might not want to adopt a younger language like Rust. Well, unless you need to get reasonably close to the metal without sacrificing safety, which is where Rust really shines. I just wrote a fast CSV sanitizer in Rust for processing gigabytes of input, and the compiler caught a subtle memory error when one CSV line spanned two buffer reads.

[1] For the sake of argument, a "good" type system in this context includes the ability to define custom collections with type parameters, it only allows NULL to appear where explicitly permitted, and it supports tagged unions with a nice "match" construct. This seems to be roughly the minimum feature set to get the full effect described above. Examples include Haskell, Elm, Rust, ML and (to a surprising extent) TypeScript.

The state of completion in the JavaScript world is fairly impressive these days, considering what it is.

Learning that there is a framework that gives you both flexibility and type safety might be a good reason to jump into Rust if you haven't already.

You can write a safe framework in Rust, or you could just have everything as Strings. Just because it's in Rust, doesn't mean you get safety from a lot of error conditions.

It's my understanding that the current Rust web framework landscape is dealing with moving over to futures (example: https://github.com/hyperium/hyper/issues/934).

The framework seems to nail the API, but what's it doing down at the bottom of the stack? Any benchmarks?

Apologies if they are somewhere obvious, but didn't see it on the site.


Today, it's built on top of hyper, which is still synchronous. It's also only using the lowest parts of hyper, apparently.

There's a branch for tokio integration, but needs the tokio 0.1 release, which is coming soon but not _quite_ out yet.

Checking the source, it looks like it uses hyper under the hood for the nuts and bolts, so presumably it will benefit from the move to futures without too much effort

This looks very much like Flask, and Flask is one of my favorite ways of writing webapps because it's just so easy to do the simple things.

Flask still unfortunately uses globals everywhere :(

What do you mean by globals?

the ´g` object is one core item, for example.

I'm not sure the syntax extension specific items are good if the intent is to present this as an argument for moving to Rust from some other language for building such a framework. I'm a bit biased: I'd avoid using syntax extensions that aren't part of the standard, because it adds a point of friction for novice and seasoned Rust developers alike.

Are you talking about the route specification syntax? It doesn't seem much worse than say flask.

In this specific case, yes those particularly would be an example.

But I don't mean in comparison to other languages or frameworks, I mean in generally, as in, I'd avoid creating syntax extensions or using them in any project.

i understand your argument but if you look at <https://news.ycombinator.com/item?id=13246361>, it seems clear to me the use of syntax extensions created an awesome developer experience that would be otherwise impossible (sure you could use the built in typesystem but then you wouldn't have human readable routes in the source)

Just a comment on the pastebin example ( https://rocket.rs/guide/pastebin/#uploading ):

UUIDs seem like it would be easier to use for demonstration : https://doc.rust-lang.org/uuid/uuid/index.html

And Cargo.toml declaration might need an extra sentence or two to explain the "features" part but that shouldn't be too bad:

    uuid = { version = "*", features = ["v4"] }

This looks pretty nice, it reminds me of Play! framework for Scala. I am curious to see if Rust or Swift will prevail for this kind of thing. Both have the opportunity to reach fairly deep into systems programming all the way up to UI and webapps.

Unrelated to the project but to the website: when I opened this on Safari my tab became consuming 52% CPU - is there something resource intensive on this site? Safari points to the clouds being a source of a lot of work.

I'd like to use it, but I need a solution which allows to use the same language on client and server.

Wait for a few months and that will start to become viable, though it probably won’t be reasonable for two or three years.

Rust 1.14, released a couple of days ago, introduced experimental support for WASM/asm.js backends. There are experiments like https://github.com/tcr/rust-todomvc which show off the possibilities. At the moment it produces a rather massive blob (over 1MB as JavaScript, not sure as WASM), but that will improve, and for some situations that doesn’t matter so much anyway.

But why would you want the same language on client and server?

as someone who knows nothing about web development, does this framework emphasize security as much as rust itself does? how does this framework compare to other rust web frameworks?

This is still very much a 0.1 release. Two relevant bugs to your question:



What color theme is that which is used in the code samples?

It seems to be Atom's One Dark: https://github.com/atom/one-dark-syntax

Very impressive. Certainly going to check it out soon.

Anyone up for writing a new web framework in another language called, say, artillery? ;)

(The counter would be missile, I guess, and then icbm... followed by planetary-defense-cannon?)

Incredible! I'm excited to use this.

Single threaded? Why not use futures?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact