Finished handy-httpd article.
This commit is contained in:
parent
ced4156cc9
commit
d875f16d33
|
@ -141,6 +141,71 @@
|
|||
}
|
||||
</code></pre>
|
||||
</figure>
|
||||
<p>
|
||||
You're not limited to only JSON though; users can upload URL-encoded data, or XML, or literally anything else. It's just that D's standard library provides a JSON implementation, so Handy-Httpd gives you some help with it.
|
||||
</p>
|
||||
<p>
|
||||
Under the hood, Handy-Httpd uses the <a href="https://github.com/andrewlalis/streams">streams</a> library for the underlying data transfer, so if you're looking for a completely custom solution, you'll need to read from <code>ctx.request.inputStream</code>, which is a <code>InputStream!ubyte</code>. Also note that each request has a pre-allocated <code>receiveBuffer</code> that you can use instead of creating your own separate buffer.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Adding Middleware with Filters</h2>
|
||||
<p>
|
||||
One of the buzz words these days in web programming is <em>"middleware"</em>, which is just a fancy term for anything that sits between two systems and performs some limited set of functions on the data that is passed between the systems.
|
||||
</p>
|
||||
<p>
|
||||
In Handy-Httpd, we've provided a convenient method of adding middleware to the HTTP request handling flow with the <code>HttpRequestFilter</code>, <code>FilterChain</code>, and the <code>FilteredRequestHandler</code>.
|
||||
</p>
|
||||
<figure>
|
||||
<img src="images/handy-httpd-filter-diagram.webp" style="max-width: 512px;">
|
||||
<figcaption>An illustration of how an HTTP request is processed by a FilteredRequestHandler: first it goes through all pre-request filters, then the underlying handler, and finally any post-request filters.</figcaption>
|
||||
</figure>
|
||||
<p>
|
||||
Suppose we want to authenticate requests to certain endpoints. That's a pretty straightforward task that many web frameworks deal with. In Handy-Httpd, you'd create a filter that reads a JWT token from the request's header, decodes it, and adds user info to the request context's <code>metadata</code> property.
|
||||
</p>
|
||||
<figure>
|
||||
<pre><code class="language-d">
|
||||
class TokenFilter : HttpRequestFilter {
|
||||
void apply(ref HttpRequestContext ctx, FilterChain filterChain) {
|
||||
Nullable!UserInfo userInfo = tryParseToken(ctx.request.getHeader("Authorization"));
|
||||
if (userInfo.isNull) {
|
||||
ctx.response.setStatus(HttpStatus.UNAUTHORIZED);
|
||||
ctx.response.writeBodyString("Invalid or missing token.");
|
||||
return; // Exit without continuing the filter chain.
|
||||
}
|
||||
ctx.metadata["userInfo"] = userInfo.get();
|
||||
filterChain.doFilter(ctx);
|
||||
}
|
||||
|
||||
private Nullable!UserInfo tryParseToken(string authHeader) {
|
||||
// Actual implementation omitted for brevity.
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</figure>
|
||||
<p>
|
||||
Then to actually use your newly-created <code>TokenFilter</code> to safeguard your endpoint, you'd use the <code>FilteredRequestHandler</code> to wrap your endpoint and set the TokenFilter as one of the pre-request filters.
|
||||
</p>
|
||||
<figure>
|
||||
<pre><code class="language-d">
|
||||
FilteredRequestHandler frh = new FilteredRequestHandler(
|
||||
mySuperSecretEndpoint,
|
||||
[new TokenFilter()]
|
||||
);
|
||||
</code></pre>
|
||||
</figure>
|
||||
<p>
|
||||
That's all there is to it! No runtime magic, just composing a handler that does exactly what you tell it to.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Additional Remarks</h2>
|
||||
<p>
|
||||
While I've done my best (which admittedly isn't that good) to keep Handy-Httpd lightweight and performant, that really isn't the number 1 goal. My goal was always to build a simple HTTP server with some nice-to-have conveniences that don't require months of diligent study to use effectively. I wanted something with sufficient documentation so that Handy-Httpd can be a D programmer's first introduction to HTTP servers.
|
||||
</p>
|
||||
<p>
|
||||
We're now on version <em>7.10.4</em> as of writing this article, and I feel like Handy-Httpd is in a place where I can comfortably say that it's reached those goals. Thanks for reading all the way through, and if you do try out Handy-Httpd, please do let me know what you think!
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<a href="../articles.html">Back to Articles</a>
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="256"
|
||||
height="256"
|
||||
viewBox="0 0 67.733332 67.733333"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:export-filename="handy-httpd-filter-diagram.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
|
||||
sodipodi:docname="handy-httpd-filter-diagram.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="2.0863221"
|
||||
inkscape:cx="158.65239"
|
||||
inkscape:cy="121.74534"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1025"
|
||||
inkscape:window-x="1080"
|
||||
inkscape:window-y="470"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<rect
|
||||
x="26.840115"
|
||||
y="32.12631"
|
||||
width="35.16235"
|
||||
height="9.0494561"
|
||||
id="rect13" />
|
||||
<rect
|
||||
x="56.108103"
|
||||
y="33.221417"
|
||||
width="50.761304"
|
||||
height="14.678366"
|
||||
id="rect3" />
|
||||
<rect
|
||||
x="56.108103"
|
||||
y="33.221417"
|
||||
width="63.776567"
|
||||
height="13.62237"
|
||||
id="rect5" />
|
||||
<rect
|
||||
x="56.108103"
|
||||
y="33.221417"
|
||||
width="155.29569"
|
||||
height="15.968712"
|
||||
id="rect10" />
|
||||
<rect
|
||||
x="56.108103"
|
||||
y="33.221417"
|
||||
width="155.29569"
|
||||
height="15.968712"
|
||||
id="rect12" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
id="rect1"
|
||||
width="94.099663"
|
||||
height="67.73333"
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:export-filename="handy-httpd-filter-diagram.webp"
|
||||
inkscape:export-xdpi="138.20241"
|
||||
inkscape:export-ydpi="138.20241" />
|
||||
<rect
|
||||
style="fill:#00741c;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
id="rect2"
|
||||
width="21.227629"
|
||||
height="10.154744"
|
||||
x="38.694527"
|
||||
y="4.6198816" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,28.202671,-0.80747154)"
|
||||
id="text2"
|
||||
style="font-weight:bold;font-size:13.3333px;line-height:14.4px;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Bold';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3);display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4.8"><tspan
|
||||
x="56.107422"
|
||||
y="44.097419"
|
||||
id="tspan2"><tspan
|
||||
style="font-weight:normal;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono'"
|
||||
id="tspan1">Server</tspan></tspan></text>
|
||||
<rect
|
||||
style="fill:#0802a0;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
id="rect4"
|
||||
width="21.227629"
|
||||
height="10.154744"
|
||||
x="38.694527"
|
||||
y="50.313068" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,27.07268,44.978735)"
|
||||
id="text4"
|
||||
style="font-weight:bold;font-size:13.3333px;line-height:14.4px;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Bold';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect5);display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4.8"><tspan
|
||||
x="56.107422"
|
||||
y="44.097419"
|
||||
id="tspan5"><tspan
|
||||
style="font-weight:normal;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono'"
|
||||
id="tspan3">Handler</tspan></tspan></text>
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
d="M -22.122026,-0.75847822 V 9.3343341 h -1.056423 l 1.783749,3.0895419 1.76871,-3.0634989 h -0.89405 V -0.76916622 Z"
|
||||
id="path5" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
d="m 32.180513,13.192201 -7.126878,7.146502 -0.74803,-0.745977 -0.918598,3.447203 3.415627,-0.920251 -0.633057,-0.631319 7.152814,-7.17251 z"
|
||||
id="path6" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
d="m 22.788774,41.777808 7.146502,7.126878 -0.745977,0.74803 3.447203,0.918598 -0.920251,-3.415627 -0.631319,0.633057 -7.17251,-7.152814 z"
|
||||
id="path7" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
d="m 67.122058,50.527486 7.126878,-7.146502 0.74803,0.745977 0.918598,-3.447203 -3.415627,0.920251 0.633057,0.631319 -7.152814,7.17251 z"
|
||||
id="path8" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.27"
|
||||
d="m 74.456161,21.941879 -7.146502,-7.126878 0.745977,-0.74803 -3.447203,-0.918598 0.920251,3.415627 0.631319,-0.633057 7.17251,7.152814 z"
|
||||
id="path9" />
|
||||
<rect
|
||||
style="fill:#bc6c00;fill-opacity:1;stroke:none;stroke-width:1.90279"
|
||||
id="rect9"
|
||||
width="38.605419"
|
||||
height="9.400876"
|
||||
x="2.9628088"
|
||||
y="27.74892" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.39641398,0,0,0.39641398,-18.050247,17.513122)"
|
||||
id="text9"
|
||||
style="font-weight:bold;font-size:8px;line-height:8.64px;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Bold';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10);display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4.8"><tspan
|
||||
x="56.107422"
|
||||
y="39.746739"
|
||||
id="tspan7"><tspan
|
||||
style="font-weight:normal;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono'"
|
||||
id="tspan6">Pre-Request Filters</tspan></tspan></text>
|
||||
<rect
|
||||
style="fill:#bc6c00;fill-opacity:1;stroke:none;stroke-width:1.94298"
|
||||
id="rect11"
|
||||
width="40.932819"
|
||||
height="9.5994463"
|
||||
x="50.481461"
|
||||
y="27.74892" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.40478721,0,0,0.40478721,28.837445,17.296917)"
|
||||
id="text11"
|
||||
style="font-weight:bold;font-size:8px;line-height:8.64px;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Bold';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect12);display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4.8"><tspan
|
||||
x="56.107422"
|
||||
y="39.746739"
|
||||
id="tspan9"><tspan
|
||||
style="font-weight:normal;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono'"
|
||||
id="tspan8">Post-Request Filters</tspan></tspan></text>
|
||||
<g
|
||||
id="g13"
|
||||
transform="translate(21.634882,9.1394129)">
|
||||
<ellipse
|
||||
style="fill:#0080bc;fill-opacity:1;stroke:none;stroke-width:1.03912"
|
||||
id="path12"
|
||||
cx="9.4012117"
|
||||
cy="8.9766521"
|
||||
rx="5.4671741"
|
||||
ry="2.5018883" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,-2.1200487,-0.74180829)"
|
||||
id="text12"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:8.64px;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect13);display:inline;fill:#bc6c00;fill-opacity:1;stroke:none;stroke-width:4.8"><tspan
|
||||
x="26.839844"
|
||||
y="38.565174"
|
||||
id="tspan11"><tspan
|
||||
style="fill:#ffffff"
|
||||
id="tspan10">Request</tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
Loading…
Reference in New Issue