<!DOCTYPE html>
<html>
<head>
<title>~ vial: a micro micro-framework ~</title>
<style type="text/css">
body {
margin: 40px auto;
max-width: 950px;
line-height: 1.6;
font-size: 20px;
color: #444;
padding: 16px;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica,
Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
}
h1:first-of-type {
text-align: center;
text-align: left;
margin-bottom: 0;
font-size: 150px;
margin-top: 40px;
}
h4:first-of-type {
margin: 0;
font-size: 50px;
color: #aaa;
margin-top: -30px;
margin-bottom: 50px;
font-weight: normal;
}
img:first-of-type {
margin-top: -20px;
margin-right: 20px;
}
h1 {
font-size: 2em;
}
h2 {
border-bottom: 1px solid #ddd;
font-size: 1.75em;
}
h1,
h2,
h3 {
line-height: 1.2;
}
p {
text-align: justify;
}
code {
white-space: pre-wrap;
}
span.smallcaps {
font-variant: small-caps;
}
span.underline {
text-decoration: underline;
}
div.column {
display: inline-block;
vertical-align: top;
width: 50%;
}
div.hanging-indent {
margin-left: 1.5em;
text-indent: -1.5em;
}
pre > code.sourceCode {
white-space: pre;
position: relative;
}
pre > code.sourceCode > span {
display: inline-block;
line-height: 1.25;
}
pre > code.sourceCode > span:empty {
height: 1.2em;
}
code.sourceCode > span {
color: inherit;
text-decoration: inherit;
}
div.sourceCode {
margin: 1em 0;
}
pre.sourceCode {
margin: 0;
}
@media screen {
div.sourceCode {
overflow: auto;
}
}
@media print {
pre > code.sourceCode {
white-space: pre-wrap;
}
pre > code.sourceCode > span {
text-indent: -5em;
padding-left: 5em;
}
}
pre.numberSource code {
counter-reset: source-line 0;
}
pre.numberSource code > span {
position: relative;
left: -4em;
counter-increment: source-line;
}
pre.numberSource code > span > a:first-child::before {
content: counter(source-line);
position: relative;
left: -1em;
text-align: right;
vertical-align: baseline;
border: none;
display: inline-block;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
padding: 0 4px;
width: 4em;
color: #aaaaaa;
}
pre.numberSource {
margin-left: 3em;
border-left: 1px solid #aaaaaa;
padding-left: 4px;
}
div.sourceCode {
}
@media screen {
pre > code.sourceCode > span > a:first-child::before {
text-decoration: underline;
}
}
code span.al {
color: #ff0000;
font-weight: bold;
}
code span.an {
color: #60a0b0;
font-weight: bold;
font-style: italic;
}
code span.at {
color: #7d9029;
}
code span.bn {
color: #40a070;
}
code span.bu {
}
code span.cf {
color: #007020;
font-weight: bold;
}
code span.ch {
color: #4070a0;
}
code span.cn {
color: #880000;
}
code span.co {
color: #60a0b0;
font-style: italic;
}
code span.cv {
color: #60a0b0;
font-weight: bold;
font-style: italic;
}
code span.do {
color: #ba2121;
font-style: italic;
}
code span.dt {
color: #902000;
}
code span.dv {
color: #40a070;
}
code span.er {
color: #ff0000;
font-weight: bold;
}
code span.ex {
}
code span.fl {
color: #40a070;
}
code span.fu {
color: #06287e;
}
code span.im {
}
code span.in {
color: #60a0b0;
font-weight: bold;
font-style: italic;
}
code span.kw {
color: #007020;
font-weight: bold;
}
code span.op {
color: #666666;
}
code span.ot {
color: #007020;
}
code span.pp {
color: #bc7a00;
}
code span.sc {
color: #4070a0;
}
code span.ss {
color: #bb6688;
}
code span.st {
color: #4070a0;
}
code span.va {
color: #19177c;
}
code span.vs {
color: #4070a0;
}
code span.wa {
color: #60a0b0;
font-weight: bold;
font-style: italic;
}
</style>
</head>
<body>
<p><img src="./img/drink-me.jpeg" alt="Drink Me." align="left" height="300" /></p>
<h1 id="vial">Vial</h1>
<h4 id="a-micro-micro-framework">~ a micro micro-framework ~</h4>
<p><strong>vial</strong> is a micro web “framework” for making micro web “sites”. It only includes a handful of basic features, hopeful that you’ll add whatever other features you need on your own. Kind of like ice cream toppings at one of those ice cream places.</p>
<p>The goal is a small, lean core that compiles quickly and has as few dependencies as possible. Use it for HTML stuff: prototyping ideas, testing out concepts, or, perhaps, even writing tiny personal apps.</p>
<p>This manual is an overview of <strong>vial</strong>’s built in features, as well as the few <em>optional</em> features you can enable. It also includes suggestions for many “common tasks”, like using a database to store information.</p>
<h2 id="hello-world">Hello, World</h2>
<p>This global greeting shows off some of <strong>vial</strong>’s built-in features.</p>
<p>You can play with it in real time by running this command in your local copy of this repository:</p>
<pre><code>$ cargo run --example manual</code></pre>
<p>Feel free to open it in your favorite text editor and poke around!</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">use</span> <span class="pp">vial::prelude::</span><span class="op">*;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="pp">routes!</span> <span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4"></a> GET <span class="st">"/"</span> <span class="op">=></span> hello_world<span class="op">;</span></span>
<span id="cb2-5"><a href="#cb2-5"></a> POST <span class="st">"/"</span> <span class="op">=></span> redirect_to_greeting<span class="op">;</span></span>
<span id="cb2-6"><a href="#cb2-6"></a> GET <span class="st">"/:name"</span> <span class="op">=></span> hello_name<span class="op">;</span></span>
<span id="cb2-7"><a href="#cb2-7"></a> GET <span class="st">"/*path"</span> <span class="op">=></span> <span class="op">|</span>req<span class="op">|</span></span>
<span id="cb2-8"><a href="#cb2-8"></a> <span class="pp">Response::</span>from(<span class="dv">404</span>)<span class="op">.</span>with_body(</span>
<span id="cb2-9"><a href="#cb2-9"></a> <span class="pp">format!</span>(<span class="st">"<h1>404 Not Found: {}</h1>"</span><span class="op">,</span></span>
<span id="cb2-10"><a href="#cb2-10"></a> req<span class="op">.</span>arg(<span class="st">"path"</span>)<span class="op">.</span>unwrap_or(<span class="st">""</span>)))<span class="op">;</span></span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="op">}</span></span>
<span id="cb2-12"><a href="#cb2-12"></a></span>
<span id="cb2-13"><a href="#cb2-13"></a><span class="kw">fn</span> hello_world(_req<span class="op">:</span> Request) <span class="op">-></span> <span class="kw">impl</span> Responder <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14"></a> <span class="st">"<h1>Hello, world!</h1></span></span>
<span id="cb2-15"><a href="#cb2-15"></a><span class="st"> <p><strong>What's your name?</strong></p></span></span>
<span id="cb2-16"><a href="#cb2-16"></a><span class="st"> <form method='POST' action='/'></span></span>
<span id="cb2-17"><a href="#cb2-17"></a><span class="st"> <p><input name='name' type='text'/></p></span></span>
<span id="cb2-18"><a href="#cb2-18"></a><span class="st"> <p><input type='submit'/></p></span></span>
<span id="cb2-19"><a href="#cb2-19"></a><span class="st"> </form>"</span></span>
<span id="cb2-20"><a href="#cb2-20"></a><span class="op">}</span></span>
<span id="cb2-21"><a href="#cb2-21"></a></span>
<span id="cb2-22"><a href="#cb2-22"></a><span class="kw">fn</span> redirect_to_greeting(req<span class="op">:</span> Request) <span class="op">-></span> <span class="dt">Option</span><span class="op"><</span><span class="kw">impl</span> Responder<span class="op">></span> <span class="op">{</span></span>
<span id="cb2-23"><a href="#cb2-23"></a> <span class="kw">let</span> name <span class="op">=</span> req<span class="op">.</span>form(<span class="st">"name"</span>)<span class="op">?;</span></span>
<span id="cb2-24"><a href="#cb2-24"></a> <span class="cn">Some</span>(<span class="pp">Response::</span>redirect_to(<span class="pp">format!</span>(<span class="st">"/{}"</span><span class="op">,</span> name)))</span>
<span id="cb2-25"><a href="#cb2-25"></a><span class="op">}</span></span>
<span id="cb2-26"><a href="#cb2-26"></a></span>
<span id="cb2-27"><a href="#cb2-27"></a><span class="kw">fn</span> hello_name(req<span class="op">:</span> Request) <span class="op">-></span> <span class="kw">impl</span> Responder <span class="op">{</span></span>
<span id="cb2-28"><a href="#cb2-28"></a> <span class="pp">format!</span>(<span class="st">"<h1>Why hello there, {}!</h1>"</span><span class="op">,</span> req<span class="op">.</span>arg(<span class="st">"name"</span>)<span class="op">.</span>unwrap())</span>
<span id="cb2-29"><a href="#cb2-29"></a><span class="op">}</span></span>
<span id="cb2-30"><a href="#cb2-30"></a></span>
<span id="cb2-31"><a href="#cb2-31"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb2-32"><a href="#cb2-32"></a> <span class="pp">run!</span>()<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb2-33"><a href="#cb2-33"></a><span class="op">}</span></span></code></pre></div>
<h2 id="getting-started">Getting Started</h2>
<ul>
<li>Add it to your project</li>
<li>Include the prelude</li>
<li>Define <code>routes!</code></li>
<li>Call <code>run!</code></li>
</ul>
<h2 id="routes">Routes</h2>
<p>Routes are written using the <code>routes!</code> macro in the format:</p>
<pre><code>HTTP_METHOD ROUTE_PATTERN => ACTION;</code></pre>
<p>The order in which routes are written matters - routes written first will be checked for matches first, meaning you can declare many routes that point to <code>"/"</code>, but only the first one declared will ever match.</p>
<p><code>HTTP_METHOD</code> can be one of:</p>
<ul>
<li><code>GET</code></li>
<li><code>HEAD</code></li>
<li><code>POST</code></li>
<li><code>PUT</code></li>
<li><code>DELETE</code></li>
<li><code>PATCH</code></li>
</ul>
<p><code>ACTION</code> can be either of:</p>
<ol type="1">
<li>A closure in the form of <code>|req| { code }</code> that returns an <code>impl Responder</code></li>
<li>The name of a function with the signature of <code>fn(Request) -> impl Responder</code>.</li>
</ol>
<p><code>ROUTE_PATTERN</code> can be an exact match, such as <code>"/user"</code> or <code>"/v2/search.php3"</code>, or it can include a named parameter:</p>
<ol type="1">
<li><code>"/:name"</code> — This will match almost anything except paths with <code>/</code> in them or with <code>.</code> in them.</li>
<li><code>"/:name.md"</code> — Use this format to match on a specific file extension.</li>
<li><code>"/*name"</code> — This will match everything, including <code>/</code>.</li>
</ol>
<p>In the three examples above, calling <code>req.arg("name")</code> in an <code>ACTION</code> will deliver <code>Some(&str)</code>.</p>
<h2 id="requests">Requests</h2>
<p>When a route matches and an <code>ACTION</code> is called, it’s passed a <a href="https://docs.rs/vial/latest/vial/struct.Request.html">Request</a> object.</p>
<ul>
<li><code>arg(&str) -> Option<&str></code></li>
<li><code>query(&str) -> Option<&str></code></li>
<li><code>form(&str) -> Option<&str></code></li>
<li><code>header(&str) -> Option<&str></code></li>
<li><code>method() -> &str</code></li>
<li><code>path() -> &str</code></li>
</ul>
<h2 id="responses">Responses</h2>
<p>All <code>ACTIONs</code> return <a href="https://docs.rs/vial/latest/vial/trait.Responder.html">Responders</a>, which are turned into <a href="https://docs.rs/vial/latest/vial/struct.Response.html">Responses</a> before being sent back to the client.</p>
<ul>
<li><code>Response::from()</code></li>
<li><code>Response::from_body()</code></li>
<li><code>Response::from_text()</code></li>
<li><code>Response::from_file()</code></li>
<li><code>Response::from_asset()</code></li>
<li><code>Response::from_code()</code></li>
</ul>
<h2 id="assets">Assets</h2>
<ul>
<li><code>static_dir!</code></li>
<li><code>asset::exists()</code></li>
<li><code>asset::path()</code></li>
</ul>
<h2 id="bundling-assets">Bundling Assets</h2>
<ul>
<li><code>vial::bundle_assets(path_to_asset_dir)</code></li>
</ul>
<h2 id="cookies">Cookies</h2>
<h2 id="sessions">Sessions</h2>
<h2 id="json">JSON</h2>
<h2 id="state">State</h2>
<h2 id="database">Database</h2>
<h2 id="markdown">Markdown</h2>
<h2 id="hatter-templates">Hatter Templates</h2>
<h2 id="horrorshow-templates">Horrorshow Templates</h2>
<h2 id="tera-templates">Tera Templates</h2>
</body>
</html>