<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zachary Churchill</title>
    <description>The latest articles on DEV Community by Zachary Churchill (@goolord).</description>
    <link>https://dev.to/goolord</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F128900%2F6d25b795-254a-47dd-a746-eb00048d80ec.jpg</url>
      <title>DEV Community: Zachary Churchill</title>
      <link>https://dev.to/goolord</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/goolord"/>
    <language>en</language>
    <item>
      <title>Using VSCode Neovim with a separate config</title>
      <dc:creator>Zachary Churchill</dc:creator>
      <pubDate>Wed, 24 Aug 2022 03:54:00 +0000</pubDate>
      <link>https://dev.to/goolord/using-vscode-neovim-with-a-separate-config-1oj0</link>
      <guid>https://dev.to/goolord/using-vscode-neovim-with-a-separate-config-1oj0</guid>
      <description>&lt;p&gt;I'm primarily a neovim user, but occasionally, for pairing with my coworkers remotely, I'll use vscode.&lt;/p&gt;

&lt;p&gt;using this option&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TyPKn7MA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l3nonup81e38b150jjky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TyPKn7MA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l3nonup81e38b150jjky.png" alt="Image description" width="880" height="136"&gt;&lt;/a&gt;&lt;br&gt;
allows you to set an init folder different from the default, as I've done here.&lt;/p&gt;

&lt;p&gt;One problem that &lt;em&gt;many&lt;/em&gt; neovim users may run into is that if you use neovim's native plugins feature (even through a package manager), any plugins that are broken or obsoleted by vscode are still in your rtp. Here's how you fix that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BFrFsvO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49s9oitcxkimdgqkm9om.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BFrFsvO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49s9oitcxkimdgqkm9om.png" alt="Image description" width="849" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--clean&lt;/code&gt; flag removes the plugins directory from your runtime path before neovim starts, you can still opt into plugins as I've done here&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rtp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;os.getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'HOME'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s1"&gt;'/.config/nvim-code'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rtp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;os.getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'HOME'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s1"&gt;'/.local/share/nvim/site/pack/packer/start/tabular/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'plugins.unload'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'settings'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'keybindings'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this helps you stay comfy when working with coworkers :)&lt;br&gt;
no more ctrl+w closing my editor for me.&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Trasa tutorial pt. 1: Type safe web routing with trasa</title>
      <dc:creator>Zachary Churchill</dc:creator>
      <pubDate>Fri, 17 May 2019 02:24:13 +0000</pubDate>
      <link>https://dev.to/goolord/trasa-tutorial-pt-1-type-safe-web-routing-with-trasa-5b1p</link>
      <guid>https://dev.to/goolord/trasa-tutorial-pt-1-type-safe-web-routing-with-trasa-5b1p</guid>
      <description>&lt;h1&gt;
  
  
  &lt;a href="https://hackage.haskell.org/package/trasa"&gt;&lt;code&gt;trasa&lt;/code&gt;&lt;/a&gt;: type safe HTTP routing and dispatch in Haskell
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Hello, World!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mFzXRF32--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3kukx3rnokmaegp7rnmd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mFzXRF32--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3kukx3rnokmaegp7rnmd.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Dependencies
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  build-depends: base ^&amp;gt;=4.12.0.0
    , trasa
    , trasa-server
    , quantification
    , bytestring
    , wai
    , wai-extra
    , warp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the sake of brevity, I'll be putting all of the code in the same cabal package. These are the minimal dependencies for getting a web server up and running. &lt;code&gt;trasa&lt;/code&gt; can leverage &lt;code&gt;wai&lt;/code&gt; and &lt;code&gt;warp&lt;/code&gt; to handle the webserver/webapp component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hackage.haskell.org/package/quantification"&gt;&lt;code&gt;quantification&lt;/code&gt;&lt;/a&gt; is maybe the only library you might not recognize here. It's used internally by &lt;code&gt;trasa&lt;/code&gt;, you'll want it in order to get better error messages and eventually to annotate some type signatures.&lt;/p&gt;

&lt;h4&gt;
  
  
  Extensions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cp"&gt;{-# language DataKinds #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# language GADTs #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# language KindSignatures #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# language OverloadedStrings #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# language ScopedTypeVariables #-}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;trasa&lt;/code&gt; uses &lt;code&gt;GADTs&lt;/code&gt; and &lt;code&gt;TypeFamilies&lt;/code&gt; extensively in its internals in an attempt to strike a balance between type level magic like seen in &lt;code&gt;servant&lt;/code&gt; and value level haskell. This tutorial only assumes familiarity with &lt;code&gt;GADTs&lt;/code&gt;, which we'll use to define a &lt;code&gt;Route&lt;/code&gt; type.&lt;/p&gt;

&lt;h4&gt;
  
  
  Imports
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.ByteString.Lazy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Functor.Identity&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Kind&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Network.Wai&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Network.Wai.Handler.Warp&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Network.Wai.Middleware.RequestLogger&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logStdoutDev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Trasa.Core&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Trasa.Server&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.ByteString.Lazy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Trasa.Method&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Our Route type
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Our route data type. We define this ourselves.&lt;/span&gt;
&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bodiedness&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="kt"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; 
    &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the route does not capture any part of the path&lt;/span&gt;
    &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the route does not capture any queries&lt;/span&gt;
    &lt;span class="kt"&gt;'Bodyless&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the route does not have a request body&lt;/span&gt;
    &lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the response body will be `ByteString`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;trasa&lt;/code&gt; is polymorphic in the 'route' type. This means we &lt;em&gt;can&lt;/em&gt; trivially deviate from a type that looks like this, such as annotating &lt;code&gt;Route&lt;/code&gt; with documentation.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;HelloWorld&lt;/code&gt; constructor represents a route that does not decode any path pieces and does not have any query parameters. For the response body, we must define a &lt;code&gt;BodyCodec&lt;/code&gt; for the request and response type we chose. &lt;code&gt;ByteString&lt;/code&gt; has the most trivial definition of a body codec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;bodyText&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;BodyCodec&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt;
&lt;span class="n"&gt;bodyText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BodyCodec&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="s"&gt;"text/html; charset=utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- ^ NonEmpty list of the HTTP media type names.&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="c1"&gt;-- ^ encode @ByteString -&amp;gt; ByteString@&lt;/span&gt;
  &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="c1"&gt;-- ^ decode @ByteString -&amp;gt; Either Text ByteString@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The utf-8 encoded &lt;code&gt;Text&lt;/code&gt; would be more correct than &lt;code&gt;ByteString&lt;/code&gt; here. If you want, you may define a &lt;code&gt;bodyText :: BodyCodec Text&lt;/code&gt; as an exercise)&lt;/p&gt;

&lt;h4&gt;
  
  
  Providing metadata for our Route type
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cd"&gt;-- | metadata about our routes: value level functions and data for constructing&lt;/span&gt;
&lt;span class="c1"&gt;--   and decoding paths&lt;/span&gt;
&lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;MetaCodec&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Meta&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- ^ match "/hello"&lt;/span&gt;
    &lt;span class="n"&gt;qend&lt;/span&gt; &lt;span class="c1"&gt;-- ^ no query parameters&lt;/span&gt;
    &lt;span class="n"&gt;bodyless&lt;/span&gt; &lt;span class="c1"&gt;-- ^ no request body&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;bodyText&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;-- ^ response body is one BodyCodec: our bodyText function above&lt;/span&gt;
    &lt;span class="kt"&gt;Method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="c1"&gt;-- ^ http method: GET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the &lt;code&gt;Route&lt;/code&gt; GADT doesn't actually carry information about our route (like its HTTP method or the textual representation of its path), we define a function where we pattern match on the data constructor and supply this information using functions from &lt;code&gt;trasa&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Route handling
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cd"&gt;-- | this function defines how we handle routes with our web server:&lt;/span&gt;
&lt;span class="c1"&gt;--   what actions we perform based on the route and its captures &amp;amp; queries&lt;/span&gt;
&lt;span class="n"&gt;routes&lt;/span&gt;
  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
     &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="c1"&gt;-- ^ our route GADT, polymorphic over its type variables&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Rec&lt;/span&gt; &lt;span class="kt"&gt;Identity&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="c1"&gt;-- ^ an extensible record of the captures for this route&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Rec&lt;/span&gt; &lt;span class="kt"&gt;Parameter&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="c1"&gt;-- ^ an extensible record of the captures for this route&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;RequestBody&lt;/span&gt; &lt;span class="kt"&gt;Identity&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the request body&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TrasaT&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="c1"&gt;-- ^ our response&lt;/span&gt;
&lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;reqBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;helloWorld&lt;/span&gt;
  &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="c1"&gt;-- | this helper function uses the `handler` function to unwrap the `Arguments` type family.&lt;/span&gt;
  &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Arguments&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TrasaT&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TrasaT&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
  &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;captures&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="n"&gt;reqBody&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

&lt;span class="n"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;TrasaT&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt;
&lt;span class="n"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function will be used by the webserver to determine what actions to take based on what Route data constructor is matched. We are presented with: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;our Route data constructor&lt;/li&gt;
&lt;li&gt;an extensible record of each value captured in the path&lt;/li&gt;
&lt;li&gt;an extensible record of each query parameter&lt;/li&gt;
&lt;li&gt;the request body&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;go&lt;/code&gt; helper function uses &lt;code&gt;handler&lt;/code&gt; to supply these to the function it's passed. The &lt;code&gt;handler&lt;/code&gt; function and &lt;code&gt;Arguments&lt;/code&gt; type family help keep everything fully polymorphic.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helloWorld&lt;/code&gt; is the function that takes all of the arguments from the captures and queries (in this case none) and resolves that to the response body type. The &lt;code&gt;TrasaT IO&lt;/code&gt; part of the type allows us to do nice error handling and IO, we will ignore boilerplate.&lt;/p&gt;

&lt;h4&gt;
  
  
  The webserver
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cd"&gt;-- | We define a list of all the routes for our server, &lt;/span&gt;
&lt;span class="c1"&gt;--   this is the only place where the type checker won't help us&lt;/span&gt;
&lt;span class="n"&gt;allRoutes&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Constructed&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;allRoutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Constructed&lt;/span&gt; &lt;span class="kt"&gt;HelloWorld&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="cd"&gt;-- | Boilerplate. This creates the data structure used to do routing&lt;/span&gt;
&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Router&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;routerWith&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapMeta&lt;/span&gt; &lt;span class="n"&gt;captureDecoding&lt;/span&gt; &lt;span class="n"&gt;captureDecoding&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;allRoutes&lt;/span&gt;

&lt;span class="cd"&gt;-- | `wai` application&lt;/span&gt;
&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Application&lt;/span&gt;
&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serveWith&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaCodecToMetaServer&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- ^ boilerplate: this just marshals some types&lt;/span&gt;
  &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="c1"&gt;-- ^ routes function defined above&lt;/span&gt;
  &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="c1"&gt;-- ^ router function defined above&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logStdoutDev&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run &lt;code&gt;cabal run&lt;/code&gt;, &lt;code&gt;xdg-open http://localhost:8080/hello&lt;/code&gt; and you should be greeted with "Hello, World!"&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mFzXRF32--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3kukx3rnokmaegp7rnmd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mFzXRF32--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3kukx3rnokmaegp7rnmd.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Captures and queries
&lt;/h2&gt;

&lt;p&gt;Ok, ok, cool. Now we can do some basic routing, but here's the best feature of trasa in my opinion: captures and queries. Say instead of "Hello, world!" we want something slightly more complicated. Say we want "$0, $1!". Let's modify the type of the HelloWorld constructor a bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bodiedness&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="kt"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; 
    &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ByteString&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;-- ^ now the path captures the first piece as a ByeString&lt;/span&gt;
    &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;'Optional&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="c1"&gt;-- ^ there is an optional query parameter, decoded as a ByteString&lt;/span&gt;
    &lt;span class="kt"&gt;'Bodyless&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the route does not have a request body&lt;/span&gt;
    &lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="c1"&gt;-- ^ the response body will be `ByteString`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we've got type errors to fix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;src/Main.hs:(37,17)-(42,14): error:
    • Couldn't match type ‘'[]’ with ‘'[ByteString]’
      Expected type: MetaCodec captures queries request response
        Actual type: Meta
                       CaptureCodec
                       CaptureCodec
                       (Many BodyCodec)
                       (Many BodyCodec)
                       '[]
                       '[]
                       'Bodyless
                       ByteString
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;   |
&lt;/span&gt;&lt;span class="gp"&gt;37 |   HelloWorld -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Meta
&lt;span class="go"&gt;   |                 ^^^^^...
src/Main.hs:54:20-29: error:
    • Couldn't match type ‘TrasaT IO ByteString’
&lt;/span&gt;&lt;span class="gp"&gt;                     with ‘ByteString -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Maybe ByteString -&amp;gt; TrasaT IO ByteString’
&lt;span class="go"&gt;      Expected type: Arguments
                       captures queries request (TrasaT IO response)
        Actual type: TrasaT IO ByteString
    • In the first argument of ‘go’, namely ‘helloWorld’
      In the expression: go helloWorld
&lt;/span&gt;&lt;span class="gp"&gt;      In a case alternative: HelloWorld -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;go helloWorld
&lt;span class="go"&gt;   |
&lt;/span&gt;&lt;span class="gp"&gt;54 |   HelloWorld -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;go helloWorld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get a slightly opaque type error in our &lt;code&gt;meta&lt;/code&gt; function, but the error from our &lt;code&gt;routes&lt;/code&gt; function is slightly more illuminating. To solve this first error, let's look at the type from three functions in &lt;code&gt;trasa&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="n"&gt;caps&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="n"&gt;caps&lt;/span&gt;
&lt;span class="n"&gt;capture&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="n"&gt;caps&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;caps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the &lt;code&gt;HelloWorld&lt;/code&gt; metadata from our &lt;code&gt;meta&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;  &lt;span class="kt"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Meta&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- ^ match "/hello"&lt;/span&gt;
    &lt;span class="n"&gt;qend&lt;/span&gt; &lt;span class="c1"&gt;-- ^ no query parameters&lt;/span&gt;
    &lt;span class="n"&gt;bodyless&lt;/span&gt; &lt;span class="c1"&gt;-- ^ no request body&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;bodyText&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;-- ^ response body is one BodyCodec: our bodyText function above&lt;/span&gt;
    &lt;span class="kt"&gt;Method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="c1"&gt;-- ^ http method: GET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The type error is telling us that the path has the type &lt;code&gt;Path cpf '[]&lt;/code&gt; because &lt;code&gt;match&lt;/code&gt; will not extend &lt;code&gt;end&lt;/code&gt;, but what the type checker is inferring is &lt;code&gt;Path cpf '[ByteString]&lt;/code&gt;. The story is similar for the query parameter. Lets solve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- add `text` as a dependency&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.Text.Encoding&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;TE&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.ByteString.Lazy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Trasa.Method&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Method&lt;/span&gt;
&lt;span class="c1"&gt;-- define a CaptureCodec for ByteString: encoding and decoding to and from text&lt;/span&gt;
&lt;span class="n"&gt;bytestring&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;CaptureCodec&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt;
&lt;span class="n"&gt;bytestring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CaptureCodec&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decodeUtf8&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toStrict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromStrict&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;TE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodeUtf8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- I'm still not going to change this to Text for now. We'll fix this later&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;helloWorld&lt;/code&gt; to take its path captures and query parameters as arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TrasaT&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="kt"&gt;ByteString&lt;/span&gt;
&lt;span class="n"&gt;helloWorld&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;", "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;
&lt;span class="n"&gt;helloWorld&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the helper functions from &lt;code&gt;trasa&lt;/code&gt; and the &lt;code&gt;bytestring&lt;/code&gt; capture codec to add metadata about how to decode the &lt;code&gt;HelloWorld&lt;/code&gt; path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;  &lt;span class="kt"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Meta&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capture&lt;/span&gt; &lt;span class="n"&gt;bytestring&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- ^ capture "/$0"&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt; &lt;span class="n"&gt;bytestring&lt;/span&gt; &lt;span class="o"&gt;.&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;qend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- ^ optionally capture "?b=$1"&lt;/span&gt;
    &lt;span class="n"&gt;bodyless&lt;/span&gt; &lt;span class="c1"&gt;-- ^ no request body&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;bodyText&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;-- ^ response body is one BodyCodec: our bodyText function above&lt;/span&gt;
    &lt;span class="kt"&gt;Method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="c1"&gt;-- ^ http method: GET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rerun, and voilà!&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HZnAtCSG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/t9ld8i5y7e2p4cc1i40n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HZnAtCSG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/t9ld8i5y7e2p4cc1i40n.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/goolord/trasa-tutorial/tree/master/trasa-ex-pt1"&gt;https://github.com/goolord/trasa-tutorial/tree/master/trasa-ex-pt1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>webserver</category>
    </item>
  </channel>
</rss>
