beginners

ppandis 2025-06-26T20:35:32.877259Z

Hello, I'm struggling to understand how to read form parameters in reitit. Is anyone aware of any well written tutorial as to how to simply read the content of body in reitit without using coercion or muuntaja (if I'm meant to use muuntaja for that? I'm not sure). In general. Can one use reitit out of the box to read path, query and form/body parameters or is it necessary to first configure all sorts of middleware? I'm trying to use ring wrap-params as middleware but without success. I've also tried to use a reitit wrapper of this but I was not sure I knew what I was doing.

p-himik 2025-06-26T21:22:00.016889Z

Muuntaja is for content negotiation and Reitit is for routing, those two concerns are orthogonal. Reitit matches based on paths. If you need only static paths, everything should work without any coercion. But if you need parameterized paths, like /api/user/:user-id where :user-id can be anything, you need for something to parse actual paths into structures that have :user-id in there as well as any other info necessary to match the path against routes. That something in the case of Reitit is coercion. You specify a particular kind of coercion not via middleware but via a separate router parameter, :coercion. But you still need middleware that would use that particular coercion to, well, coerce whatever needs coercing. It's all well documented: https://cljdoc.org/d/metosin/reitit/0.9.1/doc/ring/pluggable-coercion

ThomasFuston 2025-07-05T17:38:12.310159Z

Hallo @ppandis, i am a little late to answer, but to just get parameters with wrap-params no muuntaja is needed and its pretty easy. In Reitit there are 3 places you "plugin" your middleware - one route specific, one router specific (all routes) and one app specific. here is an example from an authentication example with reitit

(def app
  (ring/ring-handler
    (ring/router
      [["/" {:get {:handler home}}]
       ["/login" {:get  {:handler login}
                  :post {:handler do-login}}]
       ["/logout" {:get {:handler do-logout}}]
       ["/auth" {:get {:handler auth}}]
       ["/admin" {:get {:handler    admin
                        ;; This Middelware is only Route specific
                        :middleware [auth/auth-middleware]}}]]
      ;; This Middleware is router specific for all routes in the current router
      {:data {:middleware [auth/wrap-session-authentication
                           wrap-params
                           wrap-keyword-params]}})
    (ring/create-default-handler)
    ;; This Middelware is app specific
    {:middleware [wrap-session
                  [wrap-resource "public"]]}))

ppandis 2025-07-07T11:24:13.471649Z

Good morning. Thank you both for the helpful info. I'll have to read/try these when I'll have the chance to dive again into this project soon.

mini 2025-06-26T04:32:43.294659Z

I'm trying to apply the "Functional Core, Imperative Shell" pattern in Clojure and considering two directory structures: Option 1 (Layers-first):

app/
  core/         # Functional core
    users.clj
    payments.clj
    auth.clj
  shell/        # Imperative shell
    users.clj
    payments.clj
    auth.clj
Option 2 (Feature-first):
app/
  users/       # Feature module
    core.clj    # Functional
    shell.clj    # Imperative
  payments/
    core.clj
    shell.clj
  auth/
    core.clj
    shell.clj
Coming from an MVC background, I lean toward Option 1 because it mirrors a "layers" approach (separating logic from side effects). Which structure is better, and why? I asked LLMs, they're too suggesting me Option 2, what pain points does it solve compared to Option 1? or there are other options? Option 3, 4 ...?

p-himik 2025-06-26T08:28:12.121209Z

The pattern itself does not necessitate any particular directory structure, it could easily be e.g.

app/
  users.clj
  payments.clj
  auth.clj
And that's probably what I would use myself unless there are good reasons to further separate the code. Option 1 make things look neater but it's also harder to navigate around. When working on users you will almost inevitably have to first open one users.clj then go to the other, which could be a couple of scrolls away in the project view if you have many files. Option 2 doesn't suffer from that much, but it's still twice as many files than I myself would prefer. It's very similar to how e.g. re-frame docs suggest splitting a particular functionality into subs, views, events, db. But usually when you need to work on something, you end up needing all four files anyway, so there's very little point in splitting everything up, and it ends up being detrimental overall, even though it might look neater at the onset.

➕ 3
p-himik 2025-06-26T08:37:32.512659Z

I'm currently working on a project where every bit of functionality is split into 7 files with some attempt at semantics. It's much, much harder to navigate around than it could've been. Even looking at stacktraces is painful when you have something like users mentioned in 5 different locations and you have to carefully read though stacktrace, you can't just glance at it to figure out what's going on. When having to open a specific namespace in IDE, you can't just type users, you have to type in the whole non-common prefix. Oh, right - splitting by somewhat arbitrary core and shell or by MVC or what have you implicitly incentivises putting stuff together. So suppose you have validation of users. It can be functional and you already have users/core.clj, so it feels like it makes sense to put it there. On the other hand, if you have users.clj and then maybe users/... with some other files with more niche use, you'd be thinking something like "validation is a separate concern of the users functionality, so I'll put it in users/validation.clj." It's very specific, not something arbitrary like controllers or shell or whatever, and it's alright if there ends up being 50 such files in users - the functionality will usually be much more independent than it would've been with shell and core or with models, views, controllers or with something similar.

mini 2025-06-26T09:31:53.777139Z

But how would you recommend applying the functional core, imperative shell idea then? Where do you draw that boundary if not via directory structure?

p-himik 2025-06-26T09:35:43.476699Z

As I mentioned at the start, the idea does not necessitate separation via files. It could be all one giant file for all it cares. The boundary is at the function level. It's important what you call and how you call it - not what you name things and how you organize those things.

mini 2025-06-26T09:36:39.585159Z

Ok you mean, the functional core/imperative shell boundary doesn't need to be enforced through directory structure. It's more of a semantic boundary within the code itself?

p-himik 2025-06-26T09:37:59.210519Z

Yes.

mini 2025-06-26T09:39:46.751359Z

Do you use any specific naming patterns, comments, or other semantic hints to keep that boundary clear in practice?

jaihindhreddy 2025-06-26T09:54:49.580759Z

> It's more of a semantic boundary within the code itself? That boundary is in the call-stack. The final main function is imperative, because it has side effects (, because it would be useless if it had no side effects). AFAIK the idea is to have this imperative main have as little code as possible, and have it call one or more pure functions, and the bulk of the codebase must consist of these pure functions. Because pure functions are easier to reason about and test, more of your codebase will be easier to reason about and test. This has nothing to do with how said functions are arranged in the filesystem.

p-himik 2025-06-26T09:56:27.918929Z

Do you use any specific naming patterns, comments, or other semantic hints to keep that boundary clear in practice?Not really. I don't think it's necessary since figuring out what's what in a quick manner is never needed. IMO you only need that understanding when you carefully study some code that's unknown to you (regardless of whether you've never seen it before or have already forgotten it), and then you'll know what's going on anyway. Any "it's functional" hint would add nothing of use at best and would make things worse if the function ever has to diverse from the path of purity. I'm also not a fan of applying any particular pattern throughout the whole code base because in my experience it's strictly worse than applying it only where it makes sense. For example, in my own projects I immediately set up proper integration tests starting at the public API level and ending all the way inside the DB. I really, really don't like focusing on unit tests because you have to spend an insane amount of time playing with pebbles and making sure they're all round and shiny, while what you actually care is how strong your concrete mix ends up being. To me personally all that talk about "unit tests show exactly where the failure is" or anything like it is complete nonsense - a working unit test does not guarantee that anything works, and you can only hope for that guarantee if your proper integration tests don't fail. If you don't have issues with reading stack traces, and you tap> your tests, and can run any test in an isolated manner, and can run a step-by-step debugger with conditional breakpoints, the scale of a particular test doesn't matter (unless you actually run a full-on distributed system during tests) - you can pin-point any failure very, very quickly without spending an insane amount of time on caring about every tiny detail. So suppose I have some API handler that accepts a description of changes that must be applied to a set of entities that satisfy some criteria. Of course, that criteria is also passed to the handler. With the "functional core, imperative shell" pattern, I'd either have to pass a single side-effecting function to the handler - db/execute-query! or something like that - or I'd have to have 500 tiny functions and figure out which one to call at which point in time - like set-user-name!, set-user-email!, complete-order!, and on and on. The first kind of the functional-imperative boundary makes just a tiny bit of sense but it still brings enough liability for it to be not worth it most of the time. The second kind straight up doesn't make sense here, you can't even compose such functions properly.

jaihindhreddy 2025-06-26T09:56:29.437149Z

> Do you use any specific naming patterns, comments, or other semantic hints One thing I've seen often, is to use ! at the end of names to indicate the function is non-pure. But even clojure.core doesn't follow this (`alter` for example is side effectful), so I guess there is no such convention that's consistently followed across the Clojure community.

p-himik 2025-06-26T09:59:48.039809Z

Ah yes, I do sometimes use ! at the end of function names, but deliberately in a very, very inconsistent way. At least, when viewed strictly from the purity point of view. I use it more or less consistently when the function in question is not only impure, but does something worthy of attention, where that ! is much more important than just "I change something".

💯 1
jaihindhreddy 2025-06-26T10:00:39.978379Z

fire-rockets! 🙃

mini 2025-06-26T10:08:30.719059Z

That makes sense from an experienced perspective. But as a beginner, what would you recommend focusing on instead? …because you tend to say it’s not worth using and adds more complexity than value in most cases.

daveliepmann 2025-06-26T10:10:08.531409Z

The focus for func core/imp shell in Clojure is often largely about discipline instead of directory structures or patterns. Yes names can help, and so can function or namespace docstrings, but in many contexts the important thing is just the "chop wood, carry water" diligence in pushing state and side effects out of most functions and into the boundaries of the module or system.

💯 1
daveliepmann 2025-06-26T10:11:48.877459Z

Clojure is an expressive, permissive, default-functional-but-provides-stateful tools language so I've seen many cases where devs (including myself as a beginner) paint themselves into a painful corner through a lack of discipline about where they make side effects

jaihindhreddy 2025-06-26T10:26:55.950839Z

I found it unlikely to get prescriptions from the Clojure community. But I highly agree with this: > about discipline instead of directory structures or patterns. Yes names can help, and so can function or namespace docstrings Because everyone has their own taste and workflow, I think picking an approach and trying it for a while can give you your own answer. For example, let's say something like "namespace name must have a effects segment for it to contain non-pure fns", and enforce that on your own codebase(s) for a while and see if it helps. With this particular convention, you could write your own validator that ensures that pure-namespaces never require the effectful ones:

(defn effects? [namespace]
  (boolean (re-seq #"\.effects(?:$|\.)" (name (ns-name namespace)))))

(defn depends-on-effects? [namespace]
  (some effects? (vals (ns-aliases namespace))))

;; bad namespaces not following convention
(->> (all-ns) ;; replace `all-ns` with scanning the entire classpath and also probably filter out namespaces not from the application.
   (filterv #(and (not (effects? %))
                  (depends-on-effects? %))))

p-himik 2025-06-26T10:42:42.480019Z

> picking an approach and trying it for a while can give you your own answer As long as there's a non-zero effort to try out different approaches. Otherwise that answer will invariably be the very first thing you have tried. :) Another thing that helps is proper "hammock time" with a deliberate destructuring of any epithets. A frequently repeated "easier to reason about" stanza sounds fantastic but means absolutely nothing. What's "easy" here, "easier" by how much, what exactly is "to reason"? Answers to these are also highly, highly subjective, so there's gotta be a healthy dose of introspection as you think about and experiment with different approaches. As an example, Swift folks have adopted a convention to have eachNameAsDescriptiveAsPossibleEvenIfItEndsUpBeingOffensivelyLong. Even for locals. To me, that is insanity. I can grasp a simple function in any language that uses names like f, m, i, x under a second, without reading its docstring. I can take half a minute trying to read an equivalent Swift function, it's mental suffering in its purest form. Same with figuring out what to put in some controllers.clj, or what to expect when I see such a file. Whenever I see something like that in real life, it ends up being everything that doesn't fit models.clj and views.clj, and maybe utils.clj. Whenever I tried asking people "what controllers are in this app" and "why does this entity belong to this package/namespace/file", the answers always started with a protracted "uhhhh..." often followed by git blame. It's a very easy trap to get caught in. It's easy to learn about different approaches, it's easy to start applying it and maybe even in a consistent way, it's easy to become a vivacious proponent of any such approach. It's much, much harder, and even terrifying to some, to introspect yourself and figure out all the "what"s and "why"s. If a person likes just chilling and reading awfullyLongNamesThatConveyNothing, it's their prerogative, but it's no grounds to claim that it's better via any possible metric. Anything like it could be worse that any alternative by all the objective metrics, but there will still be people swearing by it because they find comfort in such an approach.

💯 1
p-himik 2025-06-26T10:56:05.903589Z

Just an exemplary rant. I have a client that loves organizing things. IMO occasionally to an unhealthy degree of "I'm tied of socks always being in the top drawer, I should move them to the bottom one", only w.r.t. the code, of course. And he has a project that he oversees but I don't really get involved with, fortunateley. A new piece of functionality that can be described by a word or two? Great, into a separate drawer package it goes! More than a couple of words? Split it! But it must all still be in the same cabinet monorepo. All while Xcode cannot work at the monorepo level when everything is a separate module, it just can't. (That's not an argument against monorepos - I love them where they make sense.) So it's all neat and tidy and all makes sense if you're on a tour. But as soon as you actually need to find something or, god forbid, change something, you can only rely on full text search which will land you in lands uncharted. And it being Swift makes things or so much worse. An Entity is used somewhere - do you know where it came from? No you don't because importing anything is effectively :use. And due to Xcode being the worst IDE I have ever had to deal with, it often can't even navigate to Entity, or it can't navigate to every extension or usage of that entity. Such a tidy neat cabinet where nothing can be found or changed without an unhealthy amount of suffering. There are even cases where tests run locally and run in CI but break on someone else's machine because of some inane reasons anywhere on the spectrum from "it's due to caching which we can't disable" to "somehow, Palpatine returned that particular test didn't run".

1
Henry 2025-06-26T12:35:48.415789Z

Just to offer another perspective: I like to think of the shell/functional divide as a recursive thing. I usually put side effecting functions into separate namespaces, but alongside the entry point of each frame of the call stack. I visualized it in the image below. an example structure that could evolve would be

my_project
|__ core.clj ;; shell/impure, calls user and ai_chat cores
|__ user/
     |__ core.clj ;; shell/impure, calls both pure and impure functions
     |__ transform.clj ;; pure functions
     |__ management.clj ;; pure functions
     |__ db.clj ;; impure functions
|__ ai_chat/
     |__ core.clj ;; shell/impure, calls both pure and impure functions
     |__ data_wrangling.clj ;; pure functions
     |__ api.clj ;; impure functions
... etc ...
May not be everyone's favorite way, but works well for me.

2025-06-26T19:52:42.198969Z

something I notice frequently is that the imperative code in a given project is at the boundary of something outside the language. eg. a third party API, a user interface, a database etc. putting imperative code inside immutable code is a pain in the ass, and usually full of bugs. the real advantage of separating imperative code into something that wraps the rest of the code is that complexity bubbles outward from imperative code, so wrapping it increases the complexity of everything further outward in your abstraction stack. probably the best utility in clojure for doing imperative shell with immutable core is a state management library (eg. component, integrant) that turns your interfaces into the imperative world into an api - in the call stack the relatively pure app code invokes the shell code at the boundaries of the application, and the state manager keeps the biggest complexity sources in its segregated world. the inversion of control of a stateful thing doing its own initialization and then providing a thin API to the rest of the code can hide the fact that it is in fact an imperative shell wrapping your app, but the advantages of the model are present

2025-06-26T19:57:38.514749Z

the one case in my experience where it was good and useful to wrap the mutable part with an outer pure interface is when the imperative code is there for performance. eg. your matrix or graph code isn't fast enough, and the libraries don't quite fit your needs, so you make a data driven API around code that is all in place primitive array updates of course it usually suffices to use an existing matrix or graph library, and they will do the wrapping for you (just like clojure itself does over the vm) so you can treat it as pure

2025-06-26T20:21:38.596929Z

A lot was said here already which I admit to not having read it all. I sometimes just break it up in my namespace with a comment header. users.clj ;;;; Impure Vars ;;;; Pure Vars ;;;; Orchestrator ...

2025-06-26T20:25:48.628529Z

Impure Vars should only be making I/O. They should have almost no if/else conditional. Pure does everything. When you have to interleave pure and impure you do it in orchestrator