# Best way to implement a "front controller" with Racket's web server

**URL:** <https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193>\
**Category:** Questions & Answers\
**Tags:** question, web-server, web\
**Created:** [October 2, 2024, 1:10am UTC](https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193 "2024-10-02T01:10:52Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![badkins](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/badkins/32/99_2.png) [@badkins](https://racket.discourse.group/u/badkins)\
**Post date:** [October 2, 2024, 1:10am UTC](https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193/1 "2024-10-02T01:10:52Z")

</div>

This question is primarily directed to @jeapostrophe , but anyone can feel free to comment 🙂

I think back in 2019, Jay mentioned my use of `web-server/dispatchers/dispatch-lift` in [Axio](https://github.com/lojic/axio-alpha) was less than ideal, and I never bothered to follow up for more detail re: why. I'm not using continuations, and I simply want a straightforward way for the Racket web server to dispatch to my own "front controller", and using `dispatch-lift` seemed like the most straightforward way to dispatch to a function.

The relevant code is [`axio-app-init`](https://github.com/lojic/axio-alpha/blob/master/axio-lib/private/axio-app.rkt#L39-L54) and [`front-controller`](https://github.com/lojic/axio-alpha/blob/master/axio-lib/private/axio-app.rkt#L67-L88)

If there's a better way to get the web server to call my front controller, I'm all ears 🙂

I'm about to use @bogdan 's [`sentry`](https://docs.racket-lang.org/sentry/index.html) package to send unhandled exceptions to Sentry, so it's a good time to tweak this part of the architecture if necessary.

Thanks!

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [October 2, 2024, 4:03pm UTC](https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193/2 "2024-10-02T16:03:08Z")

</div>

Replying partly to keep track of this thread.

IIRC when I started development on Frosthaven Manager's web server, I looked at `lift:make`, too. I don't recall what for and I don't have any commit records of the experiment (sadly), but I seem to remember the primary issue being that the implementation doesn't handle continuations well:

```racket
(define ((make procedure) conn req)
(output-response/method
conn
(procedure req)
(request-method req)))

```

Again, I don't remember the specific problem, but I _think_ it had to do with adding "middleware" to the request handling and not having that work correctly in certain cases?

Jay and others can probably comment more thoroughly. I know Brian is also interested in how Koyo handles this, and I haven't dived into the code yet to find out 🙂

---

<div class="post-metadata">

**Author:** ![bogdan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/bogdan/32/8_2.png) [@bogdan](https://racket.discourse.group/u/bogdan)\
**Post date:** [October 3, 2024, 5:33am UTC](https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193/3 "2024-10-03T05:33:36Z")

</div>

If you don't want to use continuations in your application, then I don't think there's anything particularly wrong with avoiding `dispatch/servlet` and using `dispatch-lift`.

I like to put my middleware at a level below dispatchers, though, so I typically have middleware defined as procedures from a request handler to a request handler:

```scheme
(define-values (app reverse-uri)
  [("") index-page])

(define (stack handler)
  (~> handler
      (wrap-cors)
      (wrap-auth)
      (wrap-session)
      (wrap-sentry))

(dispatch/servlet (stack app))

```

where `wrap-sentry` might look like:

```scheme
(define ((wrap-sentry hdl) req . args)
  (with-handlers ([exn:fail? (lambda (e)
                               (sentry-capture-exception! e)
                               (raise e))])
    (apply hdl req args)))

```

---

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [October 8, 2024, 6:11pm UTC](https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193/4 "2024-10-08T18:11:23Z")

</div>

Bit of thread necromancy here, my apologies.

I checked the the [axio link from up above](https://github.com/lojic/axio-alpha/blob/master/axio-lib/private/axio-app.rkt#L67-L88) and noticed this bit of code:

```scheme
 (dynamic-wind void
                run
                void)

```

I was wondering about the purpose of it -- my understanding of `dynamic-wind` is that it ensures the pre and post thunks are always called before/after the value thunk regardless of continuation jumps, but if you use `void` for those thunks then it seems pointless. I went to [the docs on dynamic-wind](https://docs.racket-lang.org/reference/cont.html#%28def._%28%28quote._~23~25kernel%29._dynamic-wind%29%29) and had trouble following it. Can someone walk me through why this would be used?

---

<div class="post-metadata">

**Author:** ![badkins](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/badkins/32/99_2.png) [@badkins](https://racket.discourse.group/u/badkins)\
**Post date:** [October 9, 2024, 2:24pm UTC](https://racket.discourse.group/t/best-way-to-implement-a-front-controller-with-rackets-web-server/3193/5 "2024-10-09T14:24:02Z")

</div>

Ha! When I posted that (very old) code, I noticed the same thing re: `dynamic-wind`, and wondered if I'd get any comments 🙂

I _think_ that the `void`s may have been placeholders that never got replaced, and then maybe I went with `with-handlers` instead. I'm not expecting to use any continuations, so maybe `dynamic-wind` is unnecessary, but the post thunk may be a good place to report exceptions to Sentry.
