Jekyll2019-08-27T06:18:48+00:00/team/feed.xmlRust Network Services Working GroupA point of coordination for all things Rust and Async Async in Rust, circa 20182018-12-13T00:00:00+00:002018-12-13T00:00:00+00:00/team/2018/12/13/async-update<p>Rust 2018 has shipped, and we’re closing in on the end of the year. While we
didn’t manage to ship async/await as part of the edition itself, the
community has made quite a lot of progress toward that goal. This post
summarizes the state of play, and announces the publication of several crates
intended to facilitate use of async/await on the nightly ecosystem.</p>
<h1 id="why-asyncawait">Why async/await</h1>
<p>Before delving into the current status, it’s worth taking a moment to recap
the core motivations for async/await, and its special importance for Rust.</p>
<p>Async/await notation is a way of making asynchronous programming more
closely resemble synchronous programming. To see how this works, consider
<code class="language-rust highlighter-rouge"><span class="nn">Read</span><span class="p">::</span><span class="n">read</span></code> in <code class="language-rust highlighter-rouge"><span class="nn">std</span><span class="p">::</span><span class="n">io</span></code>:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">buf</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-></span> <span class="n">Result</span><span class="o"><</span><span class="nb">usize</span><span class="p">,</span> <span class="nn">std</span><span class="p">::</span><span class="nn">io</span><span class="p">::</span><span class="n">Error</span><span class="o">></span>
</code></pre></div></div>
<p>This synchronous method <em>blocks the current thread</em> until data has been read
into <code class="language-rust highlighter-rouge"><span class="n">buf</span></code>, then says how many bytes were read. We can build on this method
to implement <code class="language-rust highlighter-rouge"><span class="n">read_exact</span></code>, a method that <em>continues</em> reading until the buffer
is filled:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">read_exact</span><span class="o"><</span><span class="n">T</span><span class="p">:</span> <span class="n">Read</span><span class="o">></span><span class="p">(</span><span class="n">input</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">T</span><span class="p">,</span> <span class="n">buf</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-></span> <span class="n">Result</span><span class="o"><</span><span class="p">(),</span> <span class="nn">std</span><span class="p">::</span><span class="nn">io</span><span class="p">::</span><span class="n">Error</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">cursor</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="n">cursor</span> <span class="o"><</span> <span class="n">buf</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
<span class="n">cursor</span> <span class="o">+=</span> <span class="n">input</span><span class="nf">.read</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="n">buf</span><span class="p">[</span><span class="n">cursor</span><span class="o">..</span><span class="p">])</span><span class="o">?</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the asynchronous world, we want to perform similar operations, but rather
than blocking the current thread we want to leave it free to do other work
while the I/O operations complete asychronously. But actually programming
<em>directly</em> in that way is incredibly difficult. What we want is to program
<em>as if</em> I/O operations will block the current thread, but have the
compiler transform this code into more efficient asynchronous execution.</p>
<p>In short, our goal is to be able to write the following:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">async</span> <span class="k">fn</span> <span class="n">read_exact</span><span class="o"><</span><span class="n">T</span><span class="p">:</span> <span class="n">AsyncRead</span><span class="o">></span><span class="p">(</span><span class="n">input</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">T</span><span class="p">,</span> <span class="n">buf</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-></span> <span class="n">Result</span><span class="o"><</span><span class="p">(),</span> <span class="nn">std</span><span class="p">::</span><span class="nn">io</span><span class="p">::</span><span class="n">Error</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">cursor</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="n">cursor</span> <span class="o"><</span> <span class="n">buf</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
<span class="n">cursor</span> <span class="o">+=</span> <span class="nd">await!</span><span class="p">(</span><span class="n">input</span><span class="nf">.read</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="n">buf</span><span class="p">[</span><span class="n">cursor</span><span class="o">..</span><span class="p">]))</span><span class="o">?</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Comparing the two snippets, there are three changes here:</p>
<ul>
<li>
<p>We write <code class="language-rust highlighter-rouge"><span class="n">async</span></code> before <code class="language-rust highlighter-rouge"><span class="k">fn</span></code>, to signal that the function should be
asynchronously executed on its parent thread. Async functions return
their result within a <code class="language-rust highlighter-rouge"><span class="n">Future</span></code>, representing a value that must be asynchronously
computed.</p>
</li>
<li>
<p>We use the <a href="https://docs.rs/futures-preview/0.3.0-alpha.10/futures/io/trait.AsyncRead.html"><code class="language-rust highlighter-rouge"><span class="n">AsyncRead</span></code> trait</a> (from <code class="language-rust highlighter-rouge"><span class="nn">futures</span><span class="p">::</span><span class="n">io</span></code>), rather than the
<code class="language-rust highlighter-rouge"><span class="n">Read</span></code> trait. This makes an asynchronous version of the <code class="language-rust highlighter-rouge"><span class="n">read</span></code> method
available (currently provided via the <a href="https://docs.rs/futures-preview/0.3.0-alpha.10/futures/io/trait.AsyncReadExt.html"><code class="language-rust highlighter-rouge"><span class="n">AsyncReadExt</span></code> extension trait</a>).</p>
</li>
<li>
<p>We enclose the call to <code class="language-rust highlighter-rouge"><span class="n">read</span></code> with <code class="language-rust highlighter-rouge"><span class="nd">await!</span></code>, signaling that we want to
<em>simulate</em> blocking on the operation to complete.</p>
</li>
</ul>
<p>And that’s all.</p>
<p>This approach to asynchrony has proven itself in many other languages already.
But there’s an extra element in the Rust
version: borrowing. For <code class="language-rust highlighter-rouge"><span class="n">read_exact</span></code>, we are able to hold the borrows
of <code class="language-rust highlighter-rouge"><span class="n">input</span></code> and <code class="language-rust highlighter-rouge"><span class="n">buf</span></code> while we use <code class="language-rust highlighter-rouge"><span class="nd">await!</span></code> (which may actually clear
the stack and run completely unrelated code). The validity of the
borrowing is still checked, and it works largely similarly to borrowing
within synchronous code. (The main difference: the way elision works in
<code class="language-rust highlighter-rouge"><span class="k">fn</span></code> signatures.)</p>
<p>If you’ve programmed with futures in Rust before, you’ll know this is a
game changer: manual futures code generally must be restricted to <code class="language-rust highlighter-rouge"><span class="nv">'static</span></code>
data, which (in addition to its verbosity) takes it far away from
idiomatic Rust, forcing you to program with <code class="language-rust highlighter-rouge"><span class="nb">Arc</span></code> and <code class="language-rust highlighter-rouge"><span class="n">Mutex</span></code> far more
frequently than usual.</p>
<p>Below, we’ll check in on the status of various aspects of the transition to
this new world.</p>
<h1 id="the-book">The book</h1>
<p>Part of the work around async/await this year has been writing a new
book, covering the syntax, the underlying <code class="language-rust highlighter-rouge"><span class="n">Future</span></code> API, and ultimately
various programming patterns that emerge. @cramertj has written <a href="https://rust-lang.github.io/async-book/">an early
draft</a> (repo <a href="https://github.com/rust-lang/async-book">here</a>),
which is already useful for understanding these concepts.</p>
<h1 id="the-syntax">The syntax</h1>
<p>The async/await syntax itself has had an implementation on nightly for
several months now, and is being used at a fairly large scale in Google’s
Fuchsia project. You can find more detail about that usage <a href="https://github.com/rust-lang/rfcs/pull/2592#issuecomment-438894347">here</a>.</p>
<p>While there are a few remaining limitations in the implementation of the syntax,
the main issue that remains to be resolved prior to any stabilization is the
await side of the syntax. @withoutboats recently wrote a <a href="https://boats.gitlab.io/blog/post/await-syntax/">blog post</a>
describing the issues there in detail.</p>
<p>Today, <code class="language-rust highlighter-rouge"><span class="n">async</span></code> can be used in code blocks, for free functions (<code class="language-rust highlighter-rouge"><span class="n">async</span> <span class="k">fn</span></code>),
and for inherent methods. Ultimately it will be usable in trait method signatures
as well, but this is effectively blocked by <a href="https://github.com/rust-lang/rfcs/pull/2071">existential types</a>, another
feature on track to stabilization relatively soon. In the meantime, there are
several forward-compatible ways to continue using <code class="language-rust highlighter-rouge"><span class="n">async</span></code> blocks within trait
implementations, most simply by placing the <code class="language-rust highlighter-rouge"><span class="n">async</span></code> block into a <code class="language-rust highlighter-rouge"><span class="nb">Box</span></code> that
will be removable later, once existential types are stable.</p>
<h1 id="the-supporting-apis">The Supporting APIs</h1>
<p>Like many other language features, async/await also requires some support in the
standard library: shipping the <code class="language-rust highlighter-rouge"><span class="n">Future</span></code> trait (and associated machinery) in <code class="language-rust highlighter-rouge"><span class="n">std</span></code>.
That work has been a major thrust this year, and is nearing completion.</p>
<h2 id="core-futures-apis">Core futures APIs</h2>
<p>There’s currently an <a href="https://github.com/rust-lang/rfcs/pull/2592">open RFC</a> proposing stabilization of the futures
APIs, and includes a <a href="https://github.com/aturon/rfcs/blob/future/text/0000-futures.md#historical-context">fairly detailed writeup</a> of the history of
those APIs. The pull request contains a checklist of current blockers; the most
signifcant one at the moment is finalizing the <code class="language-rust highlighter-rouge"><span class="n">Waker</span></code> APIs.</p>
<h2 id="the-pin-api">The <code class="language-rust highlighter-rouge"><span class="n">Pin</span></code> API</h2>
<p>One of the underlying mechanisms supporting the futures API is the <code class="language-rust highlighter-rouge"><span class="n">Pin</span></code> type,
which is also how we enable borrowing in <code class="language-rust highlighter-rouge"><span class="n">async</span></code> blocks. This API, too, has seen
significant iteration over the course of the year. @withoutboats’s <a href="https://boats.gitlab.io/blog/post/rethinking-pin/">blog post</a>
from a few months ago covers the final design, which has also been
<a href="https://github.com/rust-lang/rust/issues/55766">proposed for stabilization</a>. The only remaining sticking point
is around type and trait naming.</p>
<h2 id="compatibility-with-futures-01">Compatibility with futures 0.1</h2>
<p>The design of the futures API had to change in breaking ways in order to support
async/await. However, there’s a large existing ecosystem of code that uses the earlier
futures 0.1 API. Luckily, we’re able to provide a rather ergonomic compatibility layer
that makes it possible to move between the two APIs easily, and hence support
incremental migration. A <a href="https://jsdw.me/posts/rust-asyncawait-preview/">recent blog post from @jsdw</a> does an excellent
job of laying out how this compatibility story works.</p>
<h1 id="some-new-crates">Some new crates</h1>
<p>In addition to the compatibility layer the Networking Working Group has also put effort
into building crates <em>directly</em> using the new futures API, in order to more fully
vet that API, to provide a smoother experience for others wanting to build code using
async/await, and to lay out a clear vision of what the new ecosystem might look like.</p>
<ul>
<li><strong><a href="https://github.com/withoutboats/romio">Romio</a></strong>, a minimal fork of Tokio based directly on the new futures API. While
Tokio proper aims to provide a comprehensive and opinionated story for the lowest-levels
of async networking code, Romio covers just the essentials: an API surface very similar
to <code class="language-rust highlighter-rouge"><span class="nn">std</span><span class="p">::</span><span class="n">net</span></code>, but supporting async/await directly. The crate includes a good bit of
documentation and examples, and @withoutboats has written a <a href="https://boats.gitlab.io/blog/post/romio/">blog post</a>
detailing lessons learned through this port.</li>
</ul>
<ul>
<li><strong><a href="https://docs.rs/http-service">http-service</a></strong>, a tiny crate building on <a href="https://docs.rs/bytes/">bytes</a>, <a href="https://docs.rs/http">http</a>, and the new futures API
to provide a common interface for http-based services using the new futures API. This crate
is partly based on the ongoing work on <a href="https://github.com/rust-net-web/tide/">Tide</a>, where the goal is to seed the ecosystem
with numerous small, useful crates of this kind that many different frameworks and libraries
can build on. As such, the API is an extraction of the one initially used internally in Tide.</li>
</ul>
<ul>
<li>Tyger (forthcoming), a small crate that builds on top of <a href="https://github.com/hyperium/hyper/">Hyper</a> to provide a direct http-service
interface (and thus usable with async/await directly, without shims).
Ultimately Tyger is likely to grow some other higher-level amenities, to complement
Hyper’s relatively low-level focus. As with http-service, the crate is an early extraction
from the Tide work and is intended to provide a small, community-driven building block that
can be used by many other crates. It will be published some time in the next few weeks.</li>
</ul>
<h1 id="the-road-ahead">The road ahead</h1>
<p>We’ve come a long way toward async/await in 2018! With the futures and pin APIs on the cusp of stabilization, we should very soon be in a position to propose stabilization of async/await
proper, hopefully shipping in the first half of 2019. It will be crucial to continue to build
out the library ecosystem around these APIs in the coming year. If you want to get involved
in any of this exciting work, please drop by the “WG-Net” channels on the <a href="https://discord.gg/rust-lang">Rust Discord</a>!</p>Aaron TuronRust 2018 has shipped, and we’re closing in on the end of the year. While we didn’t manage to ship async/await as part of the edition itself, the community has made quite a lot of progress toward that goal. This post summarizes the state of play, and announces the publication of several crates intended to facilitate use of async/await on the nightly ecosystem.Rust Web Survey 20182018-11-28T00:00:00+00:002018-11-28T00:00:00+00:00/team/2018/11/28/wg-net-survey<h1 id="introduction">Introduction</h1>
<p>We recently sent out a survey regarding the state of the current Rust web ecosystem and we got over a 1000 responses! We really appreciate the feedback from the community. This will help us continue to improve upon the state of the Rust web ecosystem. Today, we would like to go over the responses and understand the results.</p>
<h1 id="the-present">The present</h1>
<p>Rust is a relatively new language and our users reflect that, with more than 60% of them having only used it for the last two years. Coming to web development, the two most popular frameworks for building web applications are <a href="https://rocket.rs/">Rocket</a> followed by <a href="https://actix.rs">Actix</a> at 27% and 24% respectively. Some of the many other popular web frameworks currently being used to build web applications are <a href="http://ironframework.io/">Iron</a>, <a href="https://gotham.rs">Gotham</a>, <a href="https://github.com/seanmonstar/warp/">Warp</a> and <a href="https://github.com/carllerche/tower-web">Tower-web</a>. As we can see in the figure, 20% of people choose to not use any web frameworks and instead opt to build on top of the standard library or <a href="http://hyper.rs">Hyper</a> when building their services.</p>
<p><img src="/team/assets/images/wg-net-survey-frameworks.png" alt="Frameworks pie chart" width="100%" /></p>
<h1 id="the-issues">The issues</h1>
<p>Coming to what people feel is missing from the Rust networking/web ecosystem, 65% of users find the lack of examples to be the biggest issue currently with the ecosystem followed by the lack of documentation at 53%. This is something that is actively being addressed by initiatives such as the <a href="https://tokio.rs/blog/2018-10-doc-blitz/">Tokio Doc Push</a> and the <a href="https://rust-lang.github.io/async-book/">Rust async book</a>.</p>
<p>There is also users talking about the lack of a One True Framework a la <a href="https://www.djangoproject.com/">Django</a> in Python and <a href="https://rubyonrails.org/">Rails</a> in ruby. This is something which was considered by the networking work group and to this end, work has begun on <a href="https://github.com/rust-net-web/tide/">Tide</a> a framework meant to provide a good starting point for people to get started with building web applications in Rust. Another goal for Tide is to serve as documentation for people wanting to dig deeper and learn how to write such services in Rust.</p>
<p>The next issue which users mentioned is the lack of bindings for frameworks and services used when building applications. This includes bindings for applications like <a href="https://cassandra.apache.org/">Cassandra</a> a fast NoSQL database, support for running on <a href="https://kubernetes.io/">Kubernetes</a>, a container orchestration framework and <a href="https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol">LDAP</a> an authentication protocol. A few people also touch on the lack of asynchronous database access support and no idiomatic example of how to go about doing it.</p>
<p>Rust aims to make writing systems software on various platforms easier. This is not always possible though, and is shows as our users report that using OpenSSL is the biggest platform specific pain faced by them.</p>
<p>92% of our respondents have written a web application in a different language and provide information regarding what Rust can learn from those languages. People find that they miss the vast batteries included standard library present in programming languages such as Go and Python which let you write performant web applications and services straight out of the box.</p>
<p>But all is not so bleak! The Rust language continues to interest people as the most popular reason why people chose to use Rust for their web service/application was the language itself at 90%. On top of the features of the Rust languages, the next reason was the runtime performance Rust offered at 70%.</p>
<h1 id="conclusion">Conclusion</h1>
<p>After going through all the great responses, these are some of the common themes that we found:</p>
<ul>
<li>There is a lot of excitement for the future of the Rust networking and web ecosystem.</li>
<li>Most of the users are really excited for the Rust language itself.</li>
<li>The lack of documentation and examples is the major limiting factor for people to build services and applications in Rust today.</li>
<li>The basic building blocks for building robust web services are starting to stabilize, now the ecosystem built on top of these is what people are missing.</li>
</ul>Bhargav VoletiIntroductionTide’s evolving middleware approach2018-11-27T00:00:00+00:002018-11-27T00:00:00+00:00/team/2018/11/27/tide-middleware-evolution<p>Since the <a href="https://rustasync.github.io/team/2018/11/07/tide-middleware.html">last post</a> on Tide, there have been a number of excellent contributions
from a bunch of new contributors! In this post, I want to talk about the work
that <a href="http://github.com/tirr-c">@tirr-c</a> has done to substantially improve the
middleware story.</p>
<p><em>As always: if you find these topics interesting, we’d <strong>love</strong> to have your
help building Tide!</em> There’s an active pipeline of open issues, including ones
marked as good <a href="https://github.com/rust-net-web/tide/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22">starter issues</a>, and there’s ongoing discussion for what we’d
like to see in a <a href="https://github.com/rust-net-web/tide/issues/60">0.1 release</a>. Getting involved now is the best opportunity
to help shape the direction of this community-built framework!</p>
<h1 id="improving-the-middleware-trait">Improving the <code class="language-rust highlighter-rouge"><span class="n">Middleware</span></code> trait</h1>
<p>In the <a href="https://rustasync.github.io/team/2018/11/07/tide-middleware.html">last post</a>, we proposed before/after-style middleware, borrowing from the <a href="https://github.com/actix/actix-web">actix-web</a> design:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">Middleware</span><span class="o"><</span><span class="n">Data</span><span class="o">></span><span class="p">:</span> <span class="nb">Send</span> <span class="o">+</span> <span class="n">Sync</span> <span class="p">{</span>
<span class="c">/// Asynchronously transform the incoming request, or abort further handling by immediately</span>
<span class="c">/// returning a response.</span>
<span class="k">fn</span> <span class="nf">request</span><span class="p">(</span>
<span class="o">&</span><span class="k">self</span><span class="p">,</span>
<span class="n">data</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Data</span><span class="p">,</span>
<span class="n">req</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span>
<span class="n">params</span><span class="p">:</span> <span class="o">&</span><span class="n">RouteMatch</span><span class="o"><</span><span class="nv">'_</span><span class="o">></span><span class="p">,</span>
<span class="p">)</span> <span class="k">-></span> <span class="n">FutureObj</span><span class="o"><</span><span class="nv">'static</span><span class="p">,</span> <span class="n">Result</span><span class="o"><</span><span class="n">Request</span><span class="p">,</span> <span class="n">Response</span><span class="o">>></span><span class="p">;</span>
<span class="c">/// Asynchronously transform the outgoing response.</span>
<span class="k">fn</span> <span class="nf">response</span><span class="p">(</span>
<span class="o">&</span><span class="k">self</span><span class="p">,</span>
<span class="n">data</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Data</span><span class="p">,</span>
<span class="n">head</span><span class="p">:</span> <span class="o">&</span><span class="n">Head</span><span class="p">,</span>
<span class="n">resp</span><span class="p">:</span> <span class="n">Response</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-></span> <span class="n">FutureObj</span><span class="o"><</span><span class="nv">'static</span><span class="p">,</span> <span class="n">Response</span><span class="o">></span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Since then, however, @tirr-c recognized that there were substantial gains to be had by instead
using an “around” design for the core trait:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/// Middleware that wraps around remaining middleware chain.</span>
<span class="k">pub</span> <span class="k">trait</span> <span class="n">Middleware</span><span class="o"><</span><span class="n">Data</span><span class="o">></span><span class="p">:</span> <span class="nb">Send</span> <span class="o">+</span> <span class="n">Sync</span> <span class="p">{</span>
<span class="c">/// Asynchronously handle the request, and return a response.</span>
<span class="k">fn</span> <span class="n">handle</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="nv">'a</span> <span class="k">self</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">RequestContext</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Data</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="n">FutureObj</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Response</span><span class="o">></span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This new interface is built using a convenient type, <code class="language-rust highlighter-rouge"><span class="n">RequestContext</span></code>, that encapsulates
all of the information middleware has at its disposal:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="n">RequestContext</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Data</span><span class="o">></span> <span class="p">{</span>
<span class="k">pub</span> <span class="n">app_data</span><span class="p">:</span> <span class="n">Data</span><span class="p">,</span>
<span class="k">pub</span> <span class="n">req</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span>
<span class="k">pub</span> <span class="n">params</span><span class="p">:</span> <span class="n">RouteMatch</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span><span class="p">,</span>
<span class="c">// plus additional, private fields</span>
<span class="p">}</span>
<span class="k">impl</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Data</span><span class="p">:</span> <span class="n">Clone</span> <span class="o">+</span> <span class="nb">Send</span><span class="o">></span> <span class="n">RequestContext</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Data</span><span class="o">></span> <span class="p">{</span>
<span class="c">/// Consume this context, and run remaining middleware chain to completion.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">FutureObj</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Response</span><span class="o">></span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In this approach, each middleware is given complete control over the remaining request-handling
pipeline. Keep in mind, however, that middleware and endpoints run <em>strictly after routing</em>,
and so the pipeline <em>must</em> return a response. (There’s an open issue for <a href="https://github.com/rust-net-web/tide/issues/82">internal redirects</a>.)</p>
<p>Notably, it’s simple to build before/after-style middleware constructors on top of this interface,
so we don’t lose that convenience. But using “around” middleware as the <em>core</em> interface has some
key advantages:</p>
<ul>
<li>
<p>It’s much simpler to communicate data between steps that take place before and after the rest
of the pipeline. With the original proposal, you would have to use the <code class="language-rust highlighter-rouge"><span class="nn">Request</span><span class="p">::</span><span class="n">extensions</span></code>
typemap to inject information for later extraction, and that information would have to be <code class="language-rust highlighter-rouge"><span class="nv">'static</span></code>.
With around middleware, all you need is a <code class="language-rust highlighter-rouge"><span class="k">let</span></code> binding, and the binding can contain borrows that
persist until after the rest of the pipeline has executed.</p>
</li>
<li>
<p>The original approach forced an allocation (of a <code class="language-rust highlighter-rouge"><span class="n">FutureObj</span></code>) for every middleware on every request.
In the new interface, a new <code class="language-rust highlighter-rouge"><span class="n">FutureObj</span></code> only needs to be allocated when the middleware is performing
asynchronous work or steps that occur after the rest of the pipeline.</p>
</li>
<li>
<p>The new interface is arguably simpler and tidier.</p>
</li>
</ul>
<p>Thanks to @tirr-c for working this all out!</p>
<h1 id="nested-routers-with-customized-middleware">Nested routers with customized middleware</h1>
<p>In the <a href="https://rustasync.github.io/team/2018/11/07/tide-middleware.html">last post</a>, middleware could only be applied at the top level, and hence all endpoints would
employ the exact same middleware. However, it can be useful to introduce middleware that applies
only to a subset of routes. Usually, such customization groups routes by their path structure, and
that’s the approach we’ve taken in Tide as well.</p>
<p>To apply middleware to a subset of routes with a common prefix, you can use <code class="language-rust highlighter-rouge"><span class="n">nest</span></code>:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">app</span> <span class="o">=</span> <span class="nn">App</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">your_data</span><span class="p">);</span>
<span class="n">app</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/some/prefix"</span><span class="p">)</span><span class="nf">.nest</span><span class="p">(|</span><span class="n">r</span><span class="p">|</span> <span class="p">{</span>
<span class="n">r</span><span class="nf">.middleware</span><span class="p">(</span><span class="n">some_middleware</span><span class="p">);</span> <span class="c">// applies to everything under `/some/prefix`</span>
<span class="n">r</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span><span class="nf">.get</span><span class="p">(</span><span class="n">prefix_top_endpoint</span><span class="p">);</span> <span class="c">// matches `/some/prefix`</span>
<span class="n">r</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/foo"</span><span class="p">)</span><span class="nf">.get</span><span class="p">(</span><span class="n">foo_endpoint</span><span class="p">);</span> <span class="c">// matches `/some/prefix/foo`</span>
<span class="p">});</span>
<span class="c">// no middleware is applied to this route</span>
<span class="n">app</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span><span class="nf">.get</span><span class="p">(</span><span class="n">index_endpoint</span><span class="p">);</span>
<span class="n">app</span><span class="nf">.serve</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</code></pre></div></div>
<p>The <code class="language-rust highlighter-rouge"><span class="n">nest</span></code> method gives you mutable access to a <em>subrouter</em> nested under the prefix you chose:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Data</span><span class="o">></span> <span class="n">Resource</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="n">Data</span><span class="o">></span> <span class="p">{</span>
<span class="c">/// "Nest" a subrouter to the path.</span>
<span class="c">///</span>
<span class="c">/// This method will build a fresh `Router` and give a mutable reference to it to the builder</span>
<span class="c">/// function. Builder can set up a subrouter using the `Router`. All middleware applied inside</span>
<span class="c">/// the builder will be local to the subrouter and its descendents.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">nest</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">builder</span><span class="p">:</span> <span class="k">impl</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="n">Router</span><span class="o"><</span><span class="n">Data</span><span class="o">></span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We expect that this same nesting setup will have many other uses over time, including <a href="https://github.com/rust-net-web/tide/issues/5">configuration</a>.</p>
<p>Thanks again go to @tirr-c for working through several iterations of this design!</p>
<h1 id="computed-values-an-example">Computed values: an example</h1>
<p>Finally, we now have a full example of using computed values for cookie parsing,
which you can find <a href="https://github.com/rust-net-web/tide/blob/master/examples/computed_values.rs">here</a>! A very important area of ongoing work will be
to see how much traditional middleware can be expressed as computed values instead.
Doing so makes reasoning much easier (since computed values are less powerful)
and eliminates some common middleware pitfalls (order dependence, amongst others).</p>
<p>We <a href="https://github.com/rust-net-web/tide/issues/84">plan to move this computed value into Tide proper</a>, and it would
be wonderful to accumulate many other such building blocks; PRs very welcome!</p>
<h1 id="whats-next">What’s next?</h1>
<p>It’s been an exciting couple of weeks since Tide’s initial code went online, with
a growing, enthusiastic contributor base already pushing it forward faster than I’d
dared to hope! Building on this momentum, there’s a lot more we want to tackle; here
are some highlights.</p>
<h2 id="routing">Routing</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/62">Issue 62</a>): Provide a “catch-all” routing mechanism, often expressed as <code class="language-rust highlighter-rouge"><span class="o">*</span></code> in routing syntax, which will match any path with a given prefix.</li>
<li>(<a href="https://github.com/rust-net-web/tide/issues/82">Issue 82</a>): Work out a design for “internal redirects”, where middleware or endpoints can abort the current request-handling pipeline in favor of a redirected request.</li>
<li>(<a href="https://github.com/rust-net-web/tide/issues/24">Issue 24</a>): Design an API for programmatically generating URLs based on the routing table.</li>
</ul>
<h2 id="middleware">Middleware</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/73">Issue 73</a>): Make a “middleware stack” more of a first-class concept, ultimately supporting debugging and other hooks.</li>
<li>(<a href="https://github.com/rust-net-web/tide/issues/26">Issue 26</a>): Build middleware for compression.</li>
<li>(<a href="https://github.com/rust-net-web/tide/issues/61">Issue 61</a>): Provide some notion of “always-applied” middleware, which is used even if there is no matching route.</li>
</ul>
<h2 id="configuration">Configuration</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/5">Issue 5</a>): Build a configuration system, including the ability to customize extractor behavior at point in a router.</li>
</ul>
<h2 id="additional-http-methods">Additional HTTP methods</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/51">Issue 51</a>): Provide built-in support for <code class="language-rust highlighter-rouge"><span class="n">OPTIONS</span></code>.</li>
</ul>
<h2 id="testing">Testing</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/83">Issue 83</a>): Explore app testing approaches like mocking.</li>
</ul>
<h2 id="documentation">Documentation</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/77">Issue 77</a>): Start writing a high-level guide for using Tide.</li>
<li>(<a href="https://github.com/rust-net-web/tide/issues/20">Issue 20</a>): Build some larger example applications.</li>
<li>(<a href="https://github.com/rust-net-web/tide/issues/19">Issue 19</a>): Document how endpoint signatures (and hence, extractors) work.</li>
</ul>
<h2 id="a-01-release">A 0.1 release</h2>
<ul>
<li>(<a href="https://github.com/rust-net-web/tide/issues/60">Issue 60</a>): Finally, we’ve begun discussing what should land prior to a 0.1 release,
and have an initial milestone <a href="https://github.com/rust-net-web/tide/milestone/1">here</a>.</li>
</ul>
<h1 id="thanks">Thanks!</h1>
<p>Finally, a shout out to the 19 people (!) who have already contributed to Tide:</p>
<ul>
<li><a href="https://github.com/aturon">Aaron Turon</a></li>
<li><a href="https://github.com/bIgBV">Bhargav Voleti</a></li>
<li><a href="https://github.com/Stinners">Chris Stinson</a></li>
<li><a href="https://github.com/dtolnay">David Tolnay</a></li>
<li><a href="https://github.com/liufuyang">Fuyang Liu</a></li>
<li><a href="https://github.com/DeltaManiac">Harikrishnan Menon</a></li>
<li><a href="https://github.com/hseeberger">Heiko Seeberger</a></li>
<li><a href="https://github.com/hoodie">Hendrik Sollich</a></li>
<li><a href="https://github.com/fbstj">Joe ST</a></li>
<li><a href="https://github.com/jnicklas">Jonas Nicklas</a></li>
<li><a href="https://github.com/caulagi">Pradip Caulagi</a></li>
<li><a href="https://github.com/simonasker">Simon Andersson</a></li>
<li><a href="https://github.com/cramertj">Taylor Cramer</a></li>
<li><a href="https://github.com/tzilist">Theodore Zilist</a></li>
<li><a href="https://github.com/tirr-c">Wonwoo Choi</a></li>
<li><a href="https://github.com/yoshuawuyts">Yoshua Wuyts</a></li>
<li><a href="https://github.com/csmoe">csmoe</a></li>
<li><a href="https://github.com/ibaryshnikov">Il’ya Baryshnikov</a></li>
<li><a href="https://github.com/leaxoy">lixiaohui</a></li>
</ul>Aaron TuronSince the last post on Tide, there have been a number of excellent contributions from a bunch of new contributors! In this post, I want to talk about the work that @tirr-c has done to substantially improve the middleware story.Middleware in Tide2018-11-07T00:00:00+00:002018-11-07T00:00:00+00:00/team/2018/11/07/tide-middleware<p>After the <a href="https://internals.rust-lang.org/t/routing-and-extraction-in-tide-a-first-sketch/8587">positive response</a> to the routing and extraction proposal in Tide, I’m pleased to say that <strong><a href="https://github.com/rust-net-web/tide">an initial implementation is available on GitHub!</a></strong> As a testament to the strong foundation that Rust’s ecosystem provides, the basic framework implementation took only about 1,000 lines of code.</p>
<p>The repository is populated with numerous issues, including quite a few marked as <a href="https://github.com/rust-net-web/tide/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22">good first issue</a>. At this point, enough of the skeleton of Tide is in place to turn continued development into a fully collaborative effort. This is a great time to get involved and shape what will eventually become the initial 0.1 release!</p>
<p>As part of this initial implementation, I’ve also provided a simple middleware design, as well as a new idea of <em>computed values</em>. The rest of this post will cover these two additions.</p>
<h1 id="middleware">Middleware</h1>
<p>The proposed approach to middleware is pretty simple, and is drawn <em>directly</em> from actix-web:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">Middleware</span><span class="o"><</span><span class="n">Data</span><span class="o">></span><span class="p">:</span> <span class="nb">Send</span> <span class="o">+</span> <span class="n">Sync</span> <span class="p">{</span>
<span class="c">/// Asynchronously transform the incoming request, or abort further handling by immediately</span>
<span class="c">/// returning a response.</span>
<span class="k">fn</span> <span class="nf">request</span><span class="p">(</span>
<span class="o">&</span><span class="k">self</span><span class="p">,</span>
<span class="n">data</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Data</span><span class="p">,</span>
<span class="n">req</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span>
<span class="n">params</span><span class="p">:</span> <span class="o">&</span><span class="n">RouteMatch</span><span class="o"><</span><span class="nv">'_</span><span class="o">></span><span class="p">,</span>
<span class="p">)</span> <span class="k">-></span> <span class="n">FutureObj</span><span class="o"><</span><span class="nv">'static</span><span class="p">,</span> <span class="n">Result</span><span class="o"><</span><span class="n">Request</span><span class="p">,</span> <span class="n">Response</span><span class="o">>></span><span class="p">;</span>
<span class="c">/// Asynchronously transform the outgoing response.</span>
<span class="k">fn</span> <span class="nf">response</span><span class="p">(</span>
<span class="o">&</span><span class="k">self</span><span class="p">,</span>
<span class="n">data</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Data</span><span class="p">,</span>
<span class="n">head</span><span class="p">:</span> <span class="o">&</span><span class="n">Head</span><span class="p">,</span>
<span class="n">resp</span><span class="p">:</span> <span class="n">Response</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-></span> <span class="n">FutureObj</span><span class="o"><</span><span class="nv">'static</span><span class="p">,</span> <span class="n">Response</span><span class="o">></span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In this design, middleware can:</p>
<ul>
<li>alter the request data before proceeding to the next middleware or the endpoint</li>
<li>perform side-effects before or after endpoint processing</li>
<li>abort further processing by directly producing a response</li>
<li>transform the response on the way out</li>
</ul>
<p>This functionality is provided via <em>asynchronous</em> functions. The use of <code class="language-rust highlighter-rouge"><span class="n">FutureObj</span></code> here reflects the current way to express boxed futures, which is expected to change to <code class="language-rust highlighter-rouge"><span class="nb">Box</span><span class="o"><</span><span class="n">Future</span><span class="o">></span></code> in the near future. While boxing the futures has some performance cost, it’s expected that the cost is extremely minimal, and boxing allows us to avoid much more complicated type tracking (and associated lengthy compile times). It’s a technique that has been proven out in frameworks like actix-web.</p>
<p>Note that the <code class="language-rust highlighter-rouge"><span class="n">Request</span></code> type is just the one from the <code class="language-rust highlighter-rouge"><span class="n">http</span></code> crate, which contains an <code class="language-rust highlighter-rouge"><span class="n">extensions</span></code> typemap that middleware can use to communicate arbitrary information to the endpoint or between its methods.</p>
<p>If you’re familiar with actix-web, you might notice that there’s no method corresponding to <code class="language-rust highlighter-rouge"><span class="n">finish</span></code>, i.e. one that runs after the response is transmitted. There’s an <a href="https://github.com/rust-net-web/tide/issues/11">issue open</a> explaining why; feel free to take a stab at it!</p>
<p>Middleware is added to an app in a similarly simple way:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o"><</span><span class="n">Data</span><span class="o">></span> <span class="n">App</span><span class="o"><</span><span class="n">Data</span><span class="o">></span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">middleware</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">middleware</span><span class="p">:</span> <span class="k">impl</span> <span class="n">Middleware</span><span class="o"><</span><span class="n">Data</span><span class="o">></span> <span class="o">+</span> <span class="nv">'static</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Self</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Ultimately we’ll want to support more fine-grained application of middleware, e.g. applying it only to a particular set of subroutes. There’s an <a href="https://github.com/rust-net-web/tide/issues/4">issue for that</a> as well.</p>
<h1 id="computed-values">Computed values</h1>
<p>While the above middleware story is simple and flexible, it’s often overkill. One new idea in Tide is <em>computed values</em>, which are values that can be produced on demand from a request. For example, you often want to parse the query portion of a URL into components. This parsing might be needed in the endpoint, or in various middleware. Rather than writing middleware to perform the parsing and stash it in <code class="language-rust highlighter-rouge"><span class="n">extensions</span></code> (which requires carefully ordering the middleware, and mucking around with request state), we can use a computed value to lazily perform the parsing as soon as it’s requested. The computed value will then <em>cache</em> the parsed result for the request, and any further uses will get the cached value.</p>
<p>Concretely, we have a <code class="language-rust highlighter-rouge"><span class="n">Compute</span></code> trait for computed values, with the required <code class="language-rust highlighter-rouge"><span class="n">compute_fresh</span></code> function saying how to compute the value from scratch, and the provided <code class="language-rust highlighter-rouge"><span class="n">compute</span></code> method handling caching automatically:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/// A value that can be computed on-demand from a request.</span>
<span class="k">trait</span> <span class="n">Compute</span><span class="p">:</span> <span class="nv">'static</span> <span class="o">+</span> <span class="n">Sync</span> <span class="o">+</span> <span class="nb">Send</span> <span class="o">+</span> <span class="n">Clone</span> <span class="o">+</span> <span class="n">Sized</span> <span class="p">{</span>
<span class="c">/// Compute the value directly from the given request.</span>
<span class="k">fn</span> <span class="nf">compute_fresh</span><span class="p">(</span><span class="n">req</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Request</span><span class="p">)</span> <span class="k">-></span> <span class="n">Self</span><span class="p">;</span>
<span class="c">/// Compute the value, or return a copy if it has already been computed for this request.</span>
<span class="k">fn</span> <span class="nf">compute</span><span class="p">(</span><span class="n">req</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Request</span><span class="p">)</span> <span class="k">-></span> <span class="n">Self</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There’s also a <code class="language-rust highlighter-rouge"><span class="n">Computed</span></code> extractor, which endpoints can use to request computed data:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Computed</span><span class="o"><</span><span class="n">T</span><span class="p">:</span> <span class="n">Compute</span><span class="o">></span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
</code></pre></div></div>
<p>So, going back to our earlier example, we might define:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">ParsedQuery</span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
<span class="k">impl</span> <span class="n">Compute</span> <span class="k">for</span> <span class="n">ParsedQuery</span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
<span class="n">async</span> <span class="k">fn</span> <span class="nf">my_endpoint</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="n">Computed</span><span class="o"><</span><span class="n">ParsedQuery</span><span class="o">></span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>
<p>and we’re done! Similarly, middleware can call <code class="language-rust highlighter-rouge"><span class="nn">ParsedQuery</span><span class="p">::</span><span class="n">compute</span></code> method directly on the request to get the value, potentially from cache.</p>
<p>The hope is that a lot of functionality that might traditionally end up in middleware can instead be expressed as computed values, which is both more ergonomic, <em>and</em> provides far more guarantees for reasoning about your code.</p>
<h1 id="whats-next">What’s next</h1>
<p>At this point, further work on Tide will happen in its repository and issue tracker, and on the #wg-net-web channel on Discord. There are a ton of open issues, including some design questions, and I encourage you to open additional issues with your own questions and ideas. As development progresses, we’ll regularly post additional blog posts laying out further design sketches and milestones.</p>Aaron TuronAfter the positive response to the routing and extraction proposal in Tide, I’m pleased to say that an initial implementation is available on GitHub! As a testament to the strong foundation that Rust’s ecosystem provides, the basic framework implementation took only about 1,000 lines of code.Routing and extraction in Tide: a first sketch2018-10-16T00:00:00+00:002018-10-16T00:00:00+00:00/team/2018/10/16/tide-routing<p>This post continues the <a href="https://rustasync.github.io/team/2018/09/11/tide.html">series on Tide</a>, sketching a <em>possible</em> design for routing and extraction that combines some of the best ideas from frameworks like <a href="https://rocket.rs/">Rocket</a>, <a href="https://actix.rs/">Actix</a>, and <a href="https://gotham.rs/">Gotham</a>.</p>
<ul>
<li>
<p><em>Routing</em> is how the framework maps from an HTTP request to an <em>endpoint</em>, i.e. a piece of code intended to handle the request.</p>
</li>
<li>
<p><em>Extraction</em> is how an endpoint accesses data from the HTTP request.</p>
</li>
</ul>
<p>The two concerns are usually somewhat coupled, because the extraction strategy shapes the signature of the endpoints that are being routed to. As we’ll see in this post, however, the coupling can be extremely loose.</p>
<p><strong><em>Nothing in this post is set in stone!</em></strong>
Rather, this is a sketch of one possible API direction, to
kick off discussion and collaboration. Please leave your thoughts on the <a href="https://internals.rust-lang.org/t/routing-and-extraction-in-tide-a-first-sketch/8587">internals post</a>.</p>
<h1 id="a-simple-example">A simple example</h1>
<p>We’ll start with a very simple example “app” built on top of the routing and extraction system from this post, and then we’ll look at that system in closer detail.</p>
<h2 id="the-data">The data</h2>
<p>The app maintains a simple in-memory list of messages:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span><span class="p">[</span><span class="nf">derive</span><span class="p">(</span><span class="n">Serialize</span><span class="p">,</span> <span class="n">Deserialize</span><span class="p">)]</span>
<span class="k">struct</span> <span class="n">Message</span> <span class="p">{</span>
<span class="n">contents</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
<span class="n">author</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="nb">String</span><span class="o">></span><span class="p">,</span>
<span class="c">// etc...</span>
<span class="p">}</span>
<span class="c">/// A handle to an in-memory list of messages</span>
<span class="nd">#[derive(Clone)]</span>
<span class="k">struct</span> <span class="n">Database</span> <span class="p">{</span> <span class="cm">/* ... */</span> <span class="p">}</span>
<span class="k">impl</span> <span class="n">Database</span> <span class="p">{</span>
<span class="c">/// Create a handle to an empty database</span>
<span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-></span> <span class="n">Database</span><span class="p">;</span>
<span class="c">/// Add a new message, returning its ID</span>
<span class="k">fn</span> <span class="nf">insert</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="k">-></span> <span class="nb">u64</span><span class="p">;</span>
<span class="c">/// Attempt to look up a message by ID</span>
<span class="k">fn</span> <span class="nf">get</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-></span> <span class="nb">Option</span><span class="o"><</span><span class="n">Message</span><span class="o">></span><span class="p">;</span>
<span class="c">/// Attempt to edit a message; returns `false`</span>
<span class="c">/// if `id` is not found.</span>
<span class="k">fn</span> <span class="nf">set</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">,</span> <span class="n">msg</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="k">-></span> <span class="nb">bool</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This tiny API is meant as a stand-in for more complex back ends. The main point of interest is that <code class="language-rust highlighter-rouge"><span class="n">Database</span></code> is a <em>handle</em> to a database, meaning that it is <code class="language-rust highlighter-rouge"><span class="n">Clone</span></code> (and uses an <code class="language-rust highlighter-rouge"><span class="nb">Arc</span></code> under the hood). We’ll see why that’s important later on.</p>
<h2 id="the-web-api-table-of-contents">The web API: table of contents</h2>
<p>We will build a simple, JSON-based web API for operating on this in-memory database. As per the <a href="https://rustasync.github.io/team/2018/09/11/tide.html">last post</a>, we’ll do this in two parts: a high-level “table of contents” showing how to route requests to endpoints, and then lower-level endpoint definitions.</p>
<p>The table of contents for the app is specified via a builder API:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="c">// The endpoints will receive a handle to the app state, i.e. a `Database` instance</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">app</span> <span class="o">=</span> <span class="nn">App</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">Database</span><span class="p">::</span><span class="nf">new</span><span class="p">());</span>
<span class="n">app</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/message"</span><span class="p">)</span><span class="nf">.post</span><span class="p">(</span><span class="n">new_message</span><span class="p">);</span>
<span class="n">app</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/message/{}"</span><span class="p">)</span><span class="nf">.get</span><span class="p">(</span><span class="n">get_message</span><span class="p">);</span>
<span class="n">app</span><span class="nf">.at</span><span class="p">(</span><span class="s">"/message/{}"</span><span class="p">)</span><span class="nf">.put</span><span class="p">(</span><span class="n">set_message</span><span class="p">);</span>
<span class="n">app</span><span class="nf">.serve</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Posting at <code class="language-rust highlighter-rouge"><span class="err">/</span><span class="n">message</span></code> creates a new message, while <code class="language-rust highlighter-rouge"><span class="err">/</span><span class="n">message</span><span class="err">/</span><span class="p">{}</span></code> allows retrieving and editing existing messages. The <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> segment matches any single URL segment (not containing a separator). We’ll see how to extract the matched data momentarily.</p>
<h2 id="the-web-api-endpoint-implementation">The web API: endpoint implementation</h2>
<p>To finish out the app, we need to implement the endpoint functions we passed into the table of contents.</p>
<h3 id="insertion">Insertion</h3>
<p>Let’s start with the <code class="language-rust highlighter-rouge"><span class="n">new_message</span></code> endpoint:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">async</span> <span class="k">fn</span> <span class="nf">new_message</span><span class="p">(</span><span class="k">mut</span> <span class="n">db</span><span class="p">:</span> <span class="n">AppState</span><span class="o"><</span><span class="n">Database</span><span class="o">></span><span class="p">,</span> <span class="n">msg</span><span class="p">:</span> <span class="n">Json</span><span class="o"><</span><span class="n">Message</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="n">Display</span><span class="o"><</span><span class="nb">usize</span><span class="o">></span> <span class="p">{</span>
<span class="n">db</span><span class="nf">.insert</span><span class="p">(</span><span class="n">msg</span><span class="err">.</span><span class="mi">0</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>First off, we’re using <code class="language-rust highlighter-rouge"><span class="n">async</span> <span class="k">fn</span></code> to write the endpoint.
This feature, currently available on Nightly, allows you to write futures-based code with ease. The function signature is equivalent to:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">new_message</span><span class="p">(</span><span class="k">mut</span> <span class="n">db</span><span class="p">:</span> <span class="n">AppState</span><span class="o"><</span><span class="n">Database</span><span class="o">></span><span class="p">,</span> <span class="n">msg</span><span class="p">:</span> <span class="n">Json</span><span class="o"><</span><span class="n">Message</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="k">impl</span> <span class="n">Future</span><span class="o"><</span><span class="n">Output</span> <span class="o">=</span> <span class="nf">Display</span><span class="p">(</span><span class="nb">usize</span><span class="p">)</span><span class="o">></span>
</code></pre></div></div>
<p>Every endpoint signature has this same form:</p>
<ul>
<li>Zero or more arguments, each of which implements the <code class="language-rust highlighter-rouge"><span class="n">Extractor</span></code> trait. The <code class="language-rust highlighter-rouge"><span class="n">Extractor</span></code>
implementation says how the argument data should be extracted from the request. Generally,
extractors are just wrapper structs with public fields.</li>
<li>An asynchronous return value that can be transformed into a response (via an <code class="language-rust highlighter-rouge"><span class="n">IntoResponse</span></code> trait)</li>
</ul>
<p>For <code class="language-rust highlighter-rouge"><span class="n">new_message</span></code>, we use two extractors: one to get a handle to the application state
(a <code class="language-rust highlighter-rouge"><span class="n">Database</span></code>), and another to extract the body (as a json-encoded <code class="language-rust highlighter-rouge"><span class="n">Message</span></code>).</p>
<p>Within the body of the function, we can use the parameters directly. The extractor wrapper
types implement <code class="language-rust highlighter-rouge"><span class="n">Deref</span></code> and <code class="language-rust highlighter-rouge"><span class="n">DerefMut</span></code>, and we can use <code class="language-rust highlighter-rouge"><span class="err">.</span><span class="mi">0</span></code> to extract the inner object when we
need ownership:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">db</span><span class="nf">.insert</span><span class="p">(</span><span class="n">msg</span><span class="err">.</span><span class="mi">0</span><span class="p">)</span>
</code></pre></div></div>
<p>Finally, we return the identifer of the inserted message, a <code class="language-rust highlighter-rouge"><span class="nf">Display</span><span class="p">(</span><span class="nb">u64</span><span class="p">)</span></code> value.
Like <code class="language-rust highlighter-rouge"><span class="n">Json</span></code>, the <code class="language-rust highlighter-rouge"><span class="n">Display</span></code> type is a decorator saying to serialize the given value
into a vanilla HTTP 200 with body generated by formattting via the <code class="language-rust highlighter-rouge"><span class="n">Display</span></code> trait.
In particular, it provides the following impl:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o"><</span><span class="n">T</span><span class="p">:</span> <span class="nn">fmt</span><span class="p">::</span><span class="n">Display</span><span class="o">></span> <span class="n">IntoResponse</span> <span class="k">for</span> <span class="n">Display</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>
<h3 id="updates">Updates</h3>
<p>Next, we’ll look at updating an existing message:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">async</span> <span class="k">fn</span> <span class="nf">set_message</span><span class="p">(</span><span class="k">mut</span> <span class="n">db</span><span class="p">:</span> <span class="n">AppState</span><span class="o"><</span><span class="n">Database</span><span class="o">></span><span class="p">,</span> <span class="n">id</span><span class="p">:</span> <span class="n">Path</span><span class="o"><</span><span class="nb">usize</span><span class="o">></span><span class="p">,</span> <span class="n">msg</span><span class="p">:</span> <span class="n">Json</span><span class="o"><</span><span class="n">Message</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="n">Result</span><span class="o"><</span><span class="p">(),</span> <span class="n">NotFound</span><span class="o">></span> <span class="p">{</span>
<span class="k">if</span> <span class="n">db</span><span class="nf">.set</span><span class="p">(</span><span class="n">id</span><span class="err">.</span><span class="mi">0</span><span class="p">,</span> <span class="n">msg</span><span class="err">.</span><span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">Ok</span><span class="p">(())</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">Err</span><span class="p">(</span><span class="n">NotFound</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The basic setup here is quite similar to <code class="language-rust highlighter-rouge"><span class="n">new_message</span></code>. However, for this endpoint we need
to extract the <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> parameter from the URL. We use the <code class="language-rust highlighter-rouge"><span class="n">Path</span></code> extractor to say that the
corresponding URL segment should parse as a <code class="language-rust highlighter-rouge"><span class="nb">usize</span></code> value. Otherwise, the arguments and body
of the function are pretty self-explanatory.</p>
<p>One important detail: the <code class="language-rust highlighter-rouge"><span class="n">Result</span></code> return value will serialize into a response via the serialization
for the type it contains. Both <code class="language-rust highlighter-rouge"><span class="p">()</span></code> and <code class="language-rust highlighter-rouge"><span class="n">NotFound</span></code> serialize to responses with empty bodies, but the former generates a 200 response code, while the latter yields 404.</p>
<p>Note that this way of structuring the return type is just an example. In practice, you’d probably
have a custom app error type with a more sophisticated serialization approach.</p>
<h3 id="retrieval">Retrieval</h3>
<p>Finally, we can implement retrieval of messages:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">async</span> <span class="k">fn</span> <span class="nf">get_message</span><span class="p">(</span><span class="k">mut</span> <span class="n">db</span><span class="p">:</span> <span class="n">AppState</span><span class="o"><</span><span class="n">Database</span><span class="o">></span><span class="p">,</span> <span class="n">id</span><span class="p">:</span> <span class="n">Path</span><span class="o"><</span><span class="nb">usize</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="n">Result</span><span class="o"><</span><span class="n">Json</span><span class="o"><</span><span class="n">Message</span><span class="o">></span><span class="p">,</span> <span class="n">NotFound</span><span class="o">></span> <span class="p">{</span>
<span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="o">=</span> <span class="n">db</span><span class="nf">.get</span><span class="p">(</span><span class="n">id</span><span class="err">.</span><span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">Ok</span><span class="p">(</span><span class="nf">Json</span><span class="p">(</span><span class="n">msg</span><span class="p">))</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">Err</span><span class="p">(</span><span class="n">NotFound</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The only twist here is that we’re using the <code class="language-rust highlighter-rouge"><span class="n">Json</span></code> marker in the success case, indicating that
we want to return a 200 response whose body is <code class="language-rust highlighter-rouge"><span class="n">Message</span></code> serialized via json.</p>
<h1 id="digging-deeper">Digging deeper</h1>
<p>Walking through the example app already introduced many of the relevant APIs, but now it’s worth
stepping back and seeing a more complete picture, as well as rationale and relationship to existing
Rust web frameworks.</p>
<h2 id="design-goals">Design goals</h2>
<p>There are a few core goals for the API design being sketched here:</p>
<ul>
<li>
<p><strong>Make it very straightforward to understand how URLs map to code</strong>.
We do this by making a sharp separation between routing and other concerns (including extraction),
and by <em>limiting the expressive power</em> of routing.</p>
</li>
<li>
<p><strong>Make extraction and response serialization ergonomic</strong>.
We do this by leveraging the trait system on both sides.</p>
</li>
<li>
<p><strong>Avoid macros and code generation at the core; prefer simple, “plain Rust” APIs</strong>. While macros can be very powerful, they can also obscure the underlying mechanics of a framework, and lead to hard-to-understand errors when things go wrong. While this is not a hard constraint, achieving the above two goals while using only “plain Rust” is a nice-to-have.</p>
</li>
<li>
<p><strong>Provide a clean mechanism for middleware and configuration</strong>. We’ll see later on how the proposed API is well-suited for extensibility and customization.</p>
</li>
</ul>
<p>The design draws ideas liberally from Rocket, Gotham, and Actix-Web, with some new twists of its own. Let’s dig in!</p>
<h2 id="routing">Routing</h2>
<p>For routing, to achieve the clarity goals, we follow these principles:</p>
<ul>
<li>Separate out routing via a “table of contents” approach, making it easy to see the overall app structure.</li>
<li>No “fallback” in route matching; use match specificity. In particular, the order in which routes are added has no effect, and you cannot have two identical routes.</li>
<li>Drive endpoint selection <em>solely</em> by URL and HTTP method. Other aspects of a request can affect middleware and the behavior of the endpoint, but <em>not</em> which endpoint is used in the successful case. So for example, middleware can perform authentication and avoid invoking the endpoint on failure, but it does this by explicitly choosing a separate way of providing a response, rather than relying on “fallback” in the router.</li>
</ul>
<p>At the core of the routing system are several data types:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/// An application, which houses application state and other top-level concerns.</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">App</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
<span class="c">/// Configures routing within an application. Routers can be nested.</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Router</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
<span class="c">/// Configures the responses for an application for a particular URL match.</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Resource</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
<span class="c">/// Embeds a typemap for providing hierarchical configuration of extractors, middleware, and more.</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Config</span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
</code></pre></div></div>
<p>The app-level and router APIs are straightforward:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="n">App</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">app_data</span><span class="p">:</span> <span class="n">AppData</span><span class="p">)</span> <span class="k">-></span> <span class="n">App</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">;</span>
<span class="c">/// Access the top-level router for the app.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">router</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Router</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">;</span>
<span class="c">/// Access the top-level configuration.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">config</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="c">/// Convenience API to add routes directly at the top level.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">at</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Resource</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">;</span>
<span class="c">/// Start up a server instance.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">serve</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">impl</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="n">Router</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="p">{</span>
<span class="c">/// Configure the router.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">config</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="c">/// Add a route.</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">at</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Resource</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The syntax for routes is very simple: URLs with zero or more <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> segments, possibly ending in a <code class="language-rust highlighter-rouge"><span class="o">*</span></code> segment (for matching an arbitrary “rest” of the URL). The <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> segments hook into the <code class="language-rust highlighter-rouge"><span class="n">Path</span></code> extractor; each <code class="language-rust highlighter-rouge"><span class="n">Path</span><span class="o"><</span><span class="n">T</span><span class="o">></span></code> argument in an endpoint extracts one such segment, in order.</p>
<p>To provide maximum clarity, the router only allows two routes to overlap if one route is <em>more specific</em> than the other; the most specific route is prefered. So, for example, the following routes can all coexist:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"/users/{}"</span>
<span class="s">"/users/{}/help"</span>
<span class="s">"/users/new"</span>
<span class="s">"/users/new/help"</span>
</code></pre></div></div>
<p>and a request at <code class="language-rust highlighter-rouge"><span class="err">/</span><span class="n">users</span><span class="err">/</span><span class="n">new</span></code> or <code class="language-rust highlighter-rouge"><span class="err">/</span><span class="n">users</span><span class="err">/</span><span class="n">new</span><span class="err">/</span><span class="n">help</span></code> will use the last two routes, respectively.</p>
<p>More generally: routes can share an identical prefix, but at some point must either have segments that don’t overlap (e.g. two different fixed strings), or exactly one of the routes must have a <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> or <code class="language-rust highlighter-rouge"><span class="o">*</span></code> segment where the other has a fixed string.</p>
<p>Once a route has been given, you get a handle to a <code class="language-rust highlighter-rouge"><span class="n">Resource</span></code>, which allows mounting endpoints or working with a router nested at that URL:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="n">Resource</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="n">get</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">endpoint</span><span class="p">:</span> <span class="k">impl</span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="n">T</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="n">put</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">endpoint</span><span class="p">:</span> <span class="k">impl</span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="n">T</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="n">post</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">endpoint</span><span class="p">:</span> <span class="k">impl</span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="n">T</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="n">delete</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">endpoint</span><span class="p">:</span> <span class="k">impl</span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="n">T</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">nest</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="k">impl</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="n">Router</span><span class="p">));</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">config</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="k">mut</span> <span class="n">Config</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If there’s a mismatch between the number of <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> or <code class="language-rust highlighter-rouge"><span class="o">*</span></code> segments and the corresponding <code class="language-rust highlighter-rouge"><span class="n">Path</span></code> and <code class="language-rust highlighter-rouge"><span class="n">Glob</span></code> extractors in an endpoint, <strong>the resource builder API will panic on endpoint registration</strong>. Hence, such mismatches are trivially caught before a server even runs.</p>
<p>Most of these methods return a handle to a <code class="language-rust highlighter-rouge"><span class="n">Config</span></code>, which makes it possible to tweak the configuration at a route or endpoint level. This post won’t go into detail on the configuration API, but the idea is that configuration, like middleware, applies in a hierarchical fashion along the routing table of contents. So, app-level configuration provides a global default, which can then be adjusted at each step along the way down a route (or even parts of a route) and an endpoint.</p>
<h2 id="endpoints">Endpoints</h2>
<p>A route terminates at an endpoint, which is an asynchronous <code class="language-rust highlighter-rouge"><span class="n">Request</span></code> to <code class="language-rust highlighter-rouge"><span class="n">Response</span></code> function:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="n">Kind</span><span class="o">></span> <span class="p">{</span>
<span class="k">type</span> <span class="n">Fut</span><span class="p">:</span> <span class="n">Future</span><span class="o"><</span><span class="n">Output</span> <span class="o">=</span> <span class="n">Response</span><span class="o">></span> <span class="o">+</span> <span class="nb">Send</span> <span class="o">+</span> <span class="nv">'static</span><span class="p">;</span>
<span class="k">fn</span> <span class="nf">call</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">state</span><span class="p">:</span> <span class="n">AppData</span><span class="p">,</span> <span class="n">req</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="o">&</span><span class="n">Config</span><span class="p">)</span> <span class="k">-></span> <span class="nn">Self</span><span class="p">::</span><span class="n">Fut</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-rust highlighter-rouge"><span class="n">Request</span></code> and <code class="language-rust highlighter-rouge"><span class="n">Response</span></code> types here are wrappers around those from the <code class="language-rust highlighter-rouge"><span class="n">http</span></code> crate; we won’t get into that part of the API in too much detail here, since most end-users won’t ever work directly with these types.</p>
<p>The endpoint is given a handle to the application state and a reference to the configuration, in addition to ownership of the <code class="language-rust highlighter-rouge"><span class="n">Request</span></code>.</p>
<p>Note that the <code class="language-rust highlighter-rouge"><span class="n">Endpoint</span></code> trait has a <code class="language-rust highlighter-rouge"><span class="n">Kind</span></code> parameter which is not used in the body of the trait. This additional parameter is what makes it possible to <em>overload</em> the mounting APIs to work with a variety of function signatures. In particular, here’s a fragment of some of the provided implementations:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/// A marker struct to avoid overlap</span>
<span class="k">struct</span> <span class="n">Ty</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
<span class="c">// An endpoint implementation for *zero* extractors.</span>
<span class="k">impl</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">AppData</span><span class="p">,</span> <span class="n">Fut</span><span class="o">></span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="n">Ty</span><span class="o"><</span><span class="n">Fut</span><span class="o">>></span> <span class="k">for</span> <span class="n">T</span>
<span class="n">where</span>
<span class="n">T</span><span class="p">:</span> <span class="nf">Fn</span><span class="p">()</span> <span class="k">-></span> <span class="n">Fut</span><span class="p">,</span>
<span class="n">F</span><span class="p">:</span> <span class="n">Future</span><span class="p">,</span>
<span class="nn">F</span><span class="p">::</span><span class="n">Output</span><span class="p">:</span> <span class="n">IntoResponse</span><span class="p">,</span>
<span class="c">// ...</span>
<span class="c">// An endpoint implementation for *one* extractor.</span>
<span class="k">impl</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">AppData</span><span class="p">,</span> <span class="n">Fut</span><span class="p">,</span> <span class="n">T0</span><span class="o">></span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="p">(</span><span class="n">Ty</span><span class="o"><</span><span class="n">T0</span><span class="o">></span><span class="p">,</span> <span class="n">Ty</span><span class="o"><</span><span class="n">Fut</span><span class="o">></span><span class="p">)</span><span class="o">></span> <span class="k">for</span> <span class="n">T</span>
<span class="n">where</span>
<span class="n">T</span><span class="p">:</span> <span class="nf">Fn</span><span class="p">(</span><span class="n">T0</span><span class="p">)</span> <span class="k">-></span> <span class="n">Fut</span><span class="p">,</span>
<span class="n">T0</span><span class="p">:</span> <span class="n">Extractor</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">,</span>
<span class="n">Fut</span><span class="p">:</span> <span class="n">Future</span><span class="p">,</span>
<span class="nn">Fut</span><span class="p">::</span><span class="n">Output</span><span class="p">:</span> <span class="n">IntoResponse</span><span class="p">,</span>
<span class="c">// ...</span>
<span class="c">// An endpoint implementation for *two* extractors.</span>
<span class="k">impl</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">AppData</span><span class="p">,</span> <span class="n">Fut</span><span class="p">,</span> <span class="n">T0</span><span class="p">,</span> <span class="n">T1</span><span class="o">></span> <span class="n">Endpoint</span><span class="o"><</span><span class="n">AppData</span><span class="p">,</span> <span class="p">(</span><span class="n">Ty</span><span class="o"><</span><span class="n">T0</span><span class="o">></span><span class="p">,</span> <span class="n">Ty</span><span class="o"><</span><span class="n">T1</span><span class="o">></span><span class="p">,</span> <span class="n">Ty</span><span class="o"><</span><span class="n">Fut</span><span class="o">></span><span class="p">)</span><span class="o">></span> <span class="k">for</span> <span class="n">T</span>
<span class="n">where</span>
<span class="n">T</span><span class="p">:</span> <span class="nf">Fn</span><span class="p">(</span><span class="n">T0</span><span class="p">,</span> <span class="n">T1</span><span class="p">)</span> <span class="k">-></span> <span class="n">Fut</span><span class="p">,</span>
<span class="n">T0</span><span class="p">:</span> <span class="n">Extractor</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">,</span>
<span class="n">T1</span><span class="p">:</span> <span class="n">Extractor</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">,</span>
<span class="n">Fut</span><span class="p">:</span> <span class="n">Future</span><span class="p">,</span>
<span class="nn">Fut</span><span class="p">::</span><span class="n">Output</span><span class="p">:</span> <span class="n">IntoResponse</span><span class="p">,</span>
<span class="c">// ...</span>
<span class="c">// and so on...</span>
</code></pre></div></div>
<p>Putting this all together, from the user’s perspective <strong>an “endpoint” is any async function where each argument type implements <code class="language-rust highlighter-rouge"><span class="n">Extractor</span></code> and where the return type implements <code class="language-rust highlighter-rouge"><span class="n">IntoResponse</span></code></strong>. This is how we provide an endpoint experience comparable to the one in Rocket (which has a similar setup), <em>without using macros or code generation</em>.</p>
<h2 id="extraction">Extraction</h2>
<p>Extractors work similarly to many other Rust frameworks. They are asynchronous functions that extract data from app state, configuration, and the request:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">Extractor</span><span class="o"><</span><span class="n">AppData</span><span class="o">></span><span class="p">:</span> <span class="n">Sized</span> <span class="p">{</span>
<span class="k">type</span> <span class="n">Error</span><span class="p">:</span> <span class="n">IntoResponse</span><span class="p">;</span>
<span class="k">type</span> <span class="n">Fut</span><span class="p">:</span> <span class="n">Future</span><span class="o"><</span><span class="n">Output</span> <span class="o">=</span> <span class="n">Result</span><span class="o"><</span><span class="n">Self</span><span class="p">,</span> <span class="nn">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">>></span> <span class="o">+</span> <span class="nb">Send</span> <span class="o">+</span> <span class="nv">'static</span><span class="p">;</span>
<span class="k">fn</span> <span class="nf">extract</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AppData</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="o">&</span><span class="n">Config</span><span class="p">,</span> <span class="n">req</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="n">Request</span><span class="p">)</span> <span class="k">-></span> <span class="nn">Self</span><span class="p">::</span><span class="n">Fut</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Note that extractors can fail with an error. Unlike in some frameworks, where this results in rerouting, this API works more like Actix-Web: the error must itself be <em>directly</em> convertable to a response, and no further routing is performed. As with Actix-Web, you can use the <code class="language-rust highlighter-rouge"><span class="n">Config</span></code> object to customize parameters of an extractor, including what kind of error it produces.</p>
<p>Much like with Actix-Web and other frameworks, we can provide a set of prebuilt extractors:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// These all implement `Extractor`:</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Json</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="k">pub</span> <span class="n">T</span><span class="p">);</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">AppState</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="k">pub</span> <span class="n">T</span><span class="p">);</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Path</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="k">pub</span> <span class="n">T</span><span class="p">);</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Glob</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="k">pub</span> <span class="n">T</span><span class="p">);</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Query</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="k">pub</span> <span class="n">T</span><span class="p">);</span>
</code></pre></div></div>
<p>Unlike with Actix-Web and Gotham, if you want to extract multiple <code class="language-rust highlighter-rouge"><span class="p">{}</span></code> matches in a URL, you do so using <em>multiple <code class="language-rust highlighter-rouge"><span class="n">Path</span></code> parameters</em>, rather than e.g. using a tuple within <code class="language-rust highlighter-rouge"><span class="n">Path</span></code>.</p>
<h2 id="serialization">Serialization</h2>
<p>Finally, an endpoint must return data that is convertable into a response:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">IntoResponse</span><span class="p">:</span> <span class="n">Sized</span> <span class="p">{</span>
<span class="k">type</span> <span class="n">Body</span><span class="p">:</span> <span class="n">BufStream</span> <span class="o">+</span> <span class="nb">Send</span> <span class="o">+</span> <span class="nv">'static</span><span class="p">;</span>
<span class="k">fn</span> <span class="nf">into_response</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="nn">http</span><span class="p">::</span><span class="n">Response</span><span class="o"><</span><span class="nn">Self</span><span class="p">::</span><span class="n">Body</span><span class="o">></span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-rust highlighter-rouge"><span class="n">Body</span></code> type here is to allow for streaming response bodies. Otherwise, this setup works identically to Rocket.</p>
<h1 id="whats-next">What’s next?</h1>
<p>In general, this API seems to take some of the most appealing aspects of existing Rust frameworks and consolidate them in a fairly streamlined way. While there are a lot of details elided from this post, it hopefully gives enough of a sketch to spark a <a href="https://internals.rust-lang.org/t/routing-and-extraction-in-tide-a-first-sketch/8587">useful discussion</a>. I’m eager for feedback on basically any aspect of what’s being laid out here.</p>
<p>If feedback is generally positive, there are a couple of next steps that can proceed in parallel:</p>
<ul>
<li>
<p>While I’ve prototyped the type system aspects of these APIs, I don’t have a working implementation yet. If we want to go forward in something like this direction, I’d love to collaborate with folks to get it working!</p>
</li>
<li>
<p>In addition to the APIs spelled out here, I’ve also put thought into middleware and configuration APIs. So, again assuming we want to head in this direction, the next post will spell out those ideas.</p>
</li>
</ul>
<p>Looking forward to hearing what you think!</p>Aaron TuronThis post continues the series on Tide, sketching a possible design for routing and extraction that combines some of the best ideas from frameworks like Rocket, Actix, and Gotham.Rising Tide: building a modular web framework in the open2018-09-11T00:00:00+00:002018-09-11T00:00:00+00:00/team/2018/09/11/tide<p>The Network Services Working Group <a href="https://rustasync.github.io/team/web-foundations/">aims to</a> improve the story for web development this year in several respects: by bolstering foundations like async/await, by improving the ecosystem of web-related crates, and by pulling these pieces together into a framework and book called <em>Tide</em>. The name “Tide” refers to “<em>a rising tide lifts all boats</em>”; the intent is to improve sharing, compatibility, and improvements across <em>all</em> web development and frameworks in Rust.</p>
<h1 id="the-role-of-web-frameworks">The role of web frameworks</h1>
<p>In a nutshell, the goal of a web framework is to let you develop web applications in a way that feels “native” to the host language. What <em>exactly</em> that means is a matter of huge debate, and most languages have multiple popular web frameworks taking different approaches.</p>
<p>In any case, the core problem is to solve various mismatches:</p>
<ul>
<li>A web app ultimately needs to speak HTTP, but programmers would generally prefer to think about the core “business logic” in purely native terms. At the simplest level, you want your core logic to work directly with things like integers and structs, rather than raw string data. But this division also applies to things like authentication, parsing URLs, or even how you express the set of services provided by your app.</li>
<li>A particularly vital aspect of the above factoring is dealing with serialization and/or templating: what kind of data appears in the raw request/response bodies, and how does it connect to Rust types?</li>
<li>Many web apps also work with databases, where there is another set of mismatches between the “native” and database-centric view of things. An object-relational mapping like <a href="http://diesel.rs/">Diesel</a> is one way of addressing this.</li>
</ul>
<p>Beyond addressing these mismatches, web frameworks sometimes have further ambitions, like:</p>
<ul>
<li>Good security by default.</li>
<li>Consistent app structuring, to make it easy to navigate a foreign codebase that uses the framework.</li>
<li>Standard versions of other concerns like thread and connection pools, etc.</li>
<li>Workflows for rapid code generation.</li>
</ul>
<p>This is hard work! It requires a large set of underlying libraries to do the grunt work, and careful design and ergonomics work on top to achieve the desired separation of concerns.</p>
<h2 id="the-vision-for-tide">The vision for Tide</h2>
<p>Our goal with Tide is twofold:</p>
<ul>
<li>First and foremost, to bolster the “grunt work” crates that provide core web functionality. Crates like <a href="https://github.com/hyperium/http">http</a> and <a href="https://github.com/servo/rust-url">url</a> are examples of relatively mature core libraries in this space. We want more such mature crates! A big part of the effort is identifying and finding ways to improve, standardize on, and/or document such crates.</li>
<li>Secondly, to build a serious framework on top of these crates, ideally as a very minimal layer. That is, whenever feasible we want to use existing crates, and when not, we want to create small, separate crates rather than a monolithic framework.</li>
</ul>
<p>All of this will also come together in a book, documenting both the underlying crates and the framework.</p>
<p>We want to do all of this in an open and collaborative way from the outset. This blog post is the first in an open-ended series exploring various design questions and seeking feedback and alternative ideas. If you want to get involved in any aspect of this work, reach out in the team-web channel on <a href="https://discord.gg/rust-lang">Discord</a>!</p>
<h1 id="kickoff-topics">Kickoff topics</h1>
<p><strong>The rest of this post aims to <em>kick off</em> discussion on a few central topics by surveying the ecosystem</strong>. We plan on having a steady stream of follow-up posts raising questions, presenting strawman ideas, and generally developing the framework as a community project.</p>
<h2 id="the-basic-service-api">The basic service API</h2>
<p>Most language ecosystems have ended up with a key interface for talking about web services in general: Ruby has <a href="https://rack.github.io/">Rack</a>, Python has <a href="https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface">WSGI</a>, Java has <a href="https://en.wikipedia.org/wiki/Java_servlet">Servlets</a>, and so on.</p>
<p>These interfaces specify what it means to be a web server, which generally looks like some kind of function that is given a request and produces a response (usually for HTTP). Having such an interface means you can decouple a web <em>framework</em> (which helps you produce such a function) from an underlying web <em>server</em> (which actually handles the work of implementing HTTP). It also makes it possible to provide generic low-level middleware that’s usable with any choice of server and framework.</p>
<p>Today in Rust most, but not all web frameworks use <a href="https://github.com/hyperium/hyper/">hyper</a> directly to provide basic HTTP functionality, which prevents this decoupling and easy middleware application. However, the tower-service crate is poised to provide a more generic interface through its <a href="https://docs.rs/tower-service/0.1/tower_service/trait.Service.html">Service trait</a>, and there is already a substantial amount of middleware as part of the <a href="https://github.com/tower-rs/tower">Tower project</a>, though it has not yet been published to crates.io.</p>
<p>In brief, the <code class="language-rust highlighter-rouge"><span class="n">Service</span></code> trait models an asynchronous request to response function, where the request and response types are themselves generic. For HTTP, these would be specialized to the types from the <code class="language-rust highlighter-rouge"><span class="n">http</span></code> crate. The trait is also set up to handle per-connection state (through the <code class="language-rust highlighter-rouge"><span class="n">NewService</span></code> factory trait) and backpressure (through the <code class="language-rust highlighter-rouge"><span class="n">ready</span></code> method).</p>
<p>There are some important open questions here:</p>
<ul>
<li>
<p>The <code class="language-rust highlighter-rouge"><span class="n">Service</span></code> trait was designed before <a href="http://aturon.github.io/2018/04/24/async-borrowing/">borrowing within async/await</a> was proposed, and it’s possible that some changes would be desirable there. In particular, in some circumstances you may have <em>borrowed</em> data that you wish to write into a response without making an extra owned copy. It’s not clear whether it’s possible to do this with the current setup. There’s an issue <a href="https://github.com/tower-rs/tower/issues/106">here</a> for further discussion.</p>
</li>
<li>
<p>While the <code class="language-rust highlighter-rouge"><span class="n">http</span></code> crate provides basic request and response types, the <em>body</em> data is treated generically. So, to establish a standard specialization of <code class="language-rust highlighter-rouge"><span class="n">Service</span></code> to HTTP, we also need to standardize those types (or constraints around them), which also means accounting for streaming bodies. A <a href="https://medium.com/@carllerche/tower-web-expanding-the-middleware-stack-f9bf55bfa109">recent post</a> about tower-web proposed one such approach, based on a new <code class="language-rust highlighter-rouge"><span class="n">BufStream</span></code> trait.</p>
</li>
</ul>
<p>In short, there’s already a very solid basis for a service abstraction in Rust, and hopefully the working group can help push toward standardization and improvements as needed. This abstraction would also act as the starting point for building Tide.</p>
<h2 id="routing-strategies">Routing strategies</h2>
<p>Taking the above abstraction for granted, you can view a web framework as a very fancy way of helping you write what is ultimately a single request-to-response function. As explained at the beginning of the post, a lot of the work that a framework does is to separate out concerns so that you can write your core business logic in a natural style.</p>
<p>A starting point for most frameworks is some system for <em>routing</em>, which maps URLs and HTTP request types to specific functions that contain business logic — often called <em>endpoints</em>. The routing mechanism is often a place where some <em>other</em> HTTP-centric concerns are dealt with, e.g. validation. Hence, it can be a defining aspect of how a framework fits together.</p>
<p>Approaches to routing tend to fall into one of three categories:</p>
<h3 id="endpoint-centric-routing">Endpoint-centric routing</h3>
<p>This is the approach taken by Rocket and Tower Web. You “decorate” a standard Rust function with attributes that include information about the URL that should map to that function, as well as how to extract various parameters and (for Rocket) to perform additional validation. Here’s a snippet from Tower Web:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span><span class="p">[</span><span class="nf">get</span><span class="p">(</span><span class="s">"/"</span><span class="p">)]</span>
<span class="nd">#[content_type(</span><span class="s">"json"</span><span class="nd">)]</span>
<span class="k">fn</span> <span class="nf">hello_world</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Result</span><span class="o"><</span><span class="n">HelloResponse</span><span class="p">,</span> <span class="p">()</span><span class="o">></span> <span class="p">{</span> <span class="o">..</span> <span class="p">}</span>
</code></pre></div></div>
<p>The appeal is clear: this setup has a very low barrier to entry, and puts all of the emphasis on the “native Rust” functions implementing the endpoints. On the other hand, it generally requires a macro-based implementation, and can be more difficult to extend or customize than some of the other approaches.</p>
<h3 id="table-of-contents-routing">Table-of-contents routing</h3>
<p>This is the approach taken by Gotham, Rouille, and Actix Web. You construct routing logic <em>separately</em> from the endpoints by using builder-style or macro-based APIs. For example, in Gotham, there’s an explicit <code class="language-rust highlighter-rouge"><span class="n">Router</span></code> data type that you can build:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">router</span><span class="p">()</span> <span class="k">-></span> <span class="n">Router</span> <span class="p">{</span>
<span class="nf">build_simple_router</span><span class="p">(|</span><span class="n">route</span><span class="p">|</span> <span class="p">{</span>
<span class="n">route</span><span class="nf">.request</span><span class="p">(</span><span class="nd">vec!</span><span class="p">[</span><span class="n">Get</span><span class="p">,</span> <span class="n">Head</span><span class="p">],</span> <span class="s">"/"</span><span class="p">)</span><span class="nf">.to</span><span class="p">(</span><span class="n">index</span><span class="p">);</span>
<span class="n">route</span><span class="nf">.get_or_head</span><span class="p">(</span><span class="s">"/products"</span><span class="p">)</span><span class="nf">.to</span><span class="p">(</span><span class="nn">products</span><span class="p">::</span><span class="n">index</span><span class="p">);</span>
<span class="n">route</span><span class="nf">.get</span><span class="p">(</span><span class="s">"/bag"</span><span class="p">)</span><span class="nf">.to</span><span class="p">(</span><span class="nn">bag</span><span class="p">::</span><span class="n">index</span><span class="p">);</span>
<span class="n">route</span><span class="nf">.scope</span><span class="p">(</span><span class="s">"/checkout"</span><span class="p">,</span> <span class="p">|</span><span class="n">route</span><span class="p">|</span> <span class="p">{</span>
<span class="n">route</span><span class="nf">.get</span><span class="p">(</span><span class="s">"/start"</span><span class="p">)</span><span class="nf">.to</span><span class="p">(</span><span class="nn">checkout</span><span class="p">::</span><span class="n">start</span><span class="p">);</span>
<span class="n">route</span>
<span class="nf">.post</span><span class="p">(</span><span class="s">"/payment_details"</span><span class="p">)</span>
<span class="nf">.to</span><span class="p">(</span><span class="nn">checkout</span><span class="p">::</span><span class="nn">payment_details</span><span class="p">::</span><span class="n">create</span><span class="p">);</span>
<span class="n">route</span>
<span class="nf">.put</span><span class="p">(</span><span class="s">"/payment_details"</span><span class="p">)</span>
<span class="nf">.to</span><span class="p">(</span><span class="nn">checkout</span><span class="p">::</span><span class="nn">payment_details</span><span class="p">::</span><span class="n">update</span><span class="p">);</span>
<span class="n">route</span><span class="nf">.post</span><span class="p">(</span><span class="s">"/complete"</span><span class="p">)</span><span class="nf">.to</span><span class="p">(</span><span class="nn">checkout</span><span class="p">::</span><span class="n">complete</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">})</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This “table of contents” factoring makes it easier to see the high-level structure of an app separately from the endpoint logic. It also facilitates dealing with multi-endpoint concerns, like a set of routes that all share a common validation requirement. On the other hand, it’s heavier weight than the endpoint-centric approach, and dealing with extraction (pulling out information from the request) tends to be more awkward.</p>
<h3 id="routing-via-free-form-composition">Routing via free-form composition</h3>
<p>This is the approach taken by Warp. In a way, this could also be termed the “router-free” approach: no distinction is made between endpoints and other aspects of an app. Instead, <em>everything</em> is a “filter”, essentially an HTTP-aware function, and you build up your app by composing filters. Routing is thus handled by specific filters:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Just the path segment "todos"...</span>
<span class="k">let</span> <span class="n">todos</span> <span class="o">=</span> <span class="nn">warp</span><span class="p">::</span><span class="nf">path</span><span class="p">(</span><span class="s">"todos"</span><span class="p">);</span>
<span class="c">// Combined with `index`, this means nothing comes after "todos".</span>
<span class="c">// So, for example: `GET /todos`, but not `GET /todos/32`.</span>
<span class="k">let</span> <span class="n">todos_index</span> <span class="o">=</span> <span class="n">todos</span><span class="nf">.and</span><span class="p">(</span><span class="nn">warp</span><span class="p">::</span><span class="nn">path</span><span class="p">::</span><span class="nf">index</span><span class="p">());</span>
<span class="c">// `GET /todos`</span>
<span class="k">let</span> <span class="n">list</span> <span class="o">=</span> <span class="nn">warp</span><span class="p">::</span><span class="nf">get2</span><span class="p">()</span>
<span class="nf">.and</span><span class="p">(</span><span class="n">todos_index</span><span class="p">)</span>
<span class="nf">.and</span><span class="p">(</span><span class="n">db</span><span class="nf">.clone</span><span class="p">())</span>
<span class="nf">.map</span><span class="p">(</span><span class="n">list_todos</span><span class="p">);</span>
<span class="c">// `POST /todos`</span>
<span class="k">let</span> <span class="n">create</span> <span class="o">=</span> <span class="nn">warp</span><span class="p">::</span><span class="nf">post2</span><span class="p">()</span>
<span class="nf">.and</span><span class="p">(</span><span class="n">todos_index</span><span class="p">)</span>
<span class="nf">.and</span><span class="p">(</span><span class="nn">warp</span><span class="p">::</span><span class="nn">body</span><span class="p">::</span><span class="nf">json</span><span class="p">())</span>
<span class="nf">.and</span><span class="p">(</span><span class="n">db</span><span class="nf">.clone</span><span class="p">())</span>
<span class="nf">.and_then</span><span class="p">(</span><span class="n">create_todo</span><span class="p">);</span>
<span class="c">// Combine our endpoints, since we want requests to match any of them:</span>
<span class="k">let</span> <span class="n">api</span> <span class="o">=</span> <span class="n">list</span>
<span class="nf">.or</span><span class="p">(</span><span class="n">create</span><span class="p">);</span>
<span class="c">// View access logs by setting `RUST_LOG=todos`.</span>
<span class="k">let</span> <span class="n">routes</span> <span class="o">=</span> <span class="n">api</span><span class="nf">.with</span><span class="p">(</span><span class="nn">warp</span><span class="p">::</span><span class="k">log</span><span class="p">(</span><span class="s">"todos"</span><span class="p">));</span>
</code></pre></div></div>
<p>It’s too early to say much about the pros and cons of this approach in Rust.</p>
<h3 id="routing-in-tide">Routing in Tide</h3>
<p>Given the lay of the land above, the question is what approach is best suited for Tide — a balance of giving maximal benefit to the ecosystem, and fitting in modularly (and hence not being <em>specific</em> to Tide).</p>
<p>At the moment, “table of contents”-style routing seems like the best fit. It’s well-established in other languages, and has been pioneered already in Rust — but could use some standardization and API review there as well. Compared to endpoint-centric routing, it’s more easily made modular/extensible. Compared to free-form composition, the tradeoffs are better understood.</p>
<p>To fully kick off this discussion, though, a strawman is helpful. The next post in this series will present one such strawman, delving into some of the API design questions that arise in table-of-contents-style routing in Rust, and examining avenues for modularity and sharing.</p>Aaron TuronThe Network Services Working Group aims to improve the story for web development this year in several respects: by bolstering foundations like async/await, by improving the ecosystem of web-related crates, and by pulling these pieces together into a framework and book called Tide. The name “Tide” refers to “a rising tide lifts all boats”; the intent is to improve sharing, compatibility, and improvements across all web development and frameworks in Rust.The WG-Net vision for Rust 20182018-08-09T00:00:00+00:002018-08-09T00:00:00+00:00/team/2018/08/09/going-live<p>Welcome to the new home of the Rust Network Services Working Group (Wg-Net)!</p>
<p>We <a href="https://internals.rust-lang.org/t/rebooting-the-network-services-working-group/8036">recently rebooted</a> the group, and since then have had two “all hands” meetings (with a roster of 40+ people):</p>
<ul>
<li><a href="https://github.com/rustasync/team/blob/master/meetings/2018-07-27.md">2018-07-27</a></li>
<li><a href="https://github.com/rustasync/team/blob/master/meetings/2018-08-03.md">2018-08-03</a></li>
</ul>
<p>The big news is that we’ve established three major areas of work, each of which has a dedicated subgroup, pair of leaders, and Discord channel for discussion. If you want to get involved in one or more of these efforts, hop on <a href="https://discord.gg/rust-lang">Discord</a> and say hello, or take a look at the <a href="https://github.com/rust-lang-nursery/net-wg/issues">issue tracker</a>.</p>
<h2 id="async-foundations"><a href="/team/async-foundations">Async foundations</a></h2>
<p><a href="/team/async-foundations">Home page</a><br />
<strong>Leads</strong>: @cramertj and @MajorBreakfast</p>
<p>Our goal is to bring async/await onto a path to stabilization and to provide documentation for asynchronous programming:</p>
<ul>
<li><strong>Futures 0.3 and async/await</strong> should be vetted, well-documented, well-integrated, future-proof, and on a clear path to stabilization.</li>
<li><strong><a href="https://rust-lang-nursery.github.io/futures-rs/">The futures-rs blog</a></strong> aims to give regular updates on the latest changes to <code class="language-rust highlighter-rouge"><span class="n">async</span></code>/<code class="language-rust highlighter-rouge"><span class="n">await</span></code> and the futures library.</li>
<li><strong>The <a href="https://github.com/rustasync/team/blob/master/async-book/src/SUMMARY.md">Asynchronous Programming in Rust book</a></strong> should have a complete draft, covering async/await, core futures concepts, Tokio, and enough of the ecosystem to give good examples and guidance. It should also explicitly talk about the stabilization situation, including how to bridge between stable 0.1 and unstable 0.3 worlds.</li>
</ul>
<p>Learn more <a href="/team/async-foundations">here</a>.</p>
<h2 id="embedded-networking-foundations"><a href="/team/embedded-foundations">Embedded networking foundations</a></h2>
<p><a href="/team/embedded-foundations">Home page</a><br />
<strong>Leads</strong>: @Nemo157 and @levex</p>
<p>Our goal is to support IoT development in Rust by:</p>
<ul>
<li><strong>Building reusable components for <code class="language-rust highlighter-rouge"><span class="n">no_std</span></code> asynchronous IO and hardware access</strong>. While <code class="language-rust highlighter-rouge"><span class="n">std</span></code> based projects have the great <code class="language-rust highlighter-rouge"><span class="n">tokio</span></code> async IO stack to build off <code class="language-rust highlighter-rouge"><span class="n">no_std</span></code> projects don’t have much at this point. We should provide basic prototype implementations to kickstart this area of development, then see how production ready we can get stuff.</li>
<li><strong>Prototyping an asynchronous IoT stack</strong> from the hardware to the application, with a focus on ensuring portability and ease of integrating alternative layers. This should be examples of how to combine the components from the previous point into an actual IoT application, preferably based on easy to acquire development kits. The ultimate goal of this could be a guide to putting together the existing components and how to integrate your own custom components.</li>
</ul>
<p>Learn more <a href="/team/embedded-foundations">here</a>.</p>
<h2 id="web-foundations"><a href="/team/web-foundations">Web foundations</a></h2>
<p><a href="/team/web-foundations">Home page</a><br />
<strong>Leads</strong>: @aturon and @yoshuawuyts</p>
<p>Our goal is to improve web programming in Rust by:</p>
<ul>
<li><strong>Bolstering web components</strong>, i.e. assessing the state of foundational crates for web programming (like <code class="language-rust highlighter-rouge"><span class="n">http</span></code> and <code class="language-rust highlighter-rouge"><span class="n">url</span></code>), and working to improve it by writing documentation and examples, making API improvements, standardizing interfaces, and in some cases writing whole new crates.</li>
<li><strong>Building <em>Tide</em></strong>, which is a combination of a simple, modular web framework built on the above components, and extensive documentation on what the components are, how to use them directly, and how they integrate into a framework. The name “Tide” refers to “a rising tide lifts all boats”, conveying the intent that this work is aimed to improve sharing, compatibility, and improvements across <em>all</em> web development and frameworks in Rust.</li>
</ul>
<p>Learn more <a href="/team/web-foundations">here</a>.</p>Welcome to the new home of the Rust Network Services Working Group (Wg-Net)!