[Guide] How to build APIs with Clojure - Feedback wanted

I know that people here at Clojureverse are more experienced, so i wanted to post here mostly for feedback, any typos or mistakes i made in this guide, i’d appreciate any feedback, thanks :grinning:

5 Likes

Excellent post! Definitely one I might have my employees/new students read. The only technical difference of opinion is to use reitit instead of Compojure, which I find much simpler and more idiomatic for beginners to grasp (data-driven rather than macro-powered).

edit suggestion: “Advice” instead of “Advices” at the bottom

Also, I’d forgotten about ClojureToolbox. Thanks for that!

1 Like

Hey Tory, thanks for the feedback!

I didn’t knew about reitit, never used before, but now I’m curious to try it, maybe I can even create an alternate version of this guide using reitit, I also think data driven is way better than macros because macros makes everything looks too obscure and magic…

1 Like

Oh, also, wanted to ask what you’d recommend for students to deal with Databases? I first used HoneySQL, and found out it was a little confusing, ended up writing my own SQL…

Asking this because this Guide will have more parts and one of them is dealing with DB, (and for the db probably I’ll use SQLite to avoid setups)

If it’s just about learning, perhaps you could do with just clojure/java.jdbc? No magic, write plain queries and get Clojure data out. Works great with the REPL, just evaluate your calls.

1 Like

This is great. I’ve been thinking about this topic a bit for the past few weeks after watching this video:

EDIT - sorry hit the enter key too quickly.

I think the getting started advice for new users should be to teach them how to build their own stack from individual libs - instead of pointing to things like Luminus. I feel like there should be a more official Getting Started Trail (maybe even on Clojure.org?) which does just that. The above video which is similar to your blog post actually encouraged me to build my side project web app in Clojure instead of a more traditional stack because I see value in owning your whole stack and understanding every part.

Regarding reitit which was recommended above, I wish there was a routing library a bit smaller in scope - perhaps just focused on ring. Perhaps because I’m new to Clojure I find reitit a bit confusing and I found I no longer fully understand my stack (which has me questioning my initial decision!). For example, I wasted a few hours trying to figure out why my sessions weren’t working until I found this issue: https://github.com/metosin/reitit/issues/205. And I’ve spent quite a bit of time jumping between all the wiki pages.

1 Like

I think Sean’s next.jdbc is a better choice - modern, simpler.
we use just that and manually write SQL. But our domain isn’t too complicated, otherwise I might consider HoneySQL.

Yeah, next.jdbc might be just as fine a choice. You might have a better understanding of their differences than I have. I like that next.jdbc uses qualified keywords for table row identification, and I would be interested in exploring the datafy/nav support.

My argument would be for learning the basics. Which can be accomplished, with clojure/java.jdbc or jdbc.next.

Just now found your comments @jonathan regarding reitit and simplicity and related to the session-middleware issue. I hear you and I think it highlights the challenges of making a routing framework vs having just a routing library.

Just using a routing library (e.g. bidi or reitit-core), you are in full control of all the things it can be considered as being simple. If that is all you need, go for it. As soon as you enter the realm of frameworks (compojure, pedestal, reitit-http, reitit-ring, yada) you fall into somewhere between simple & easy. Frameworks, by definition, inverse the control and call your registered code when they need to do so. You lose some control, but might gain some simplicity as the boilerplate code to wire things together is done for you.

In reitit-ring (a routing framework!), there are few hiccups, which relate to the ring-model. One of them is the session-middleware issue you referenced. There is actually a pending PR to fix that but not fun to lose hours for figuring that out. We’ll try to simplify things for Reitit 1.0.0. Also, docs could be much better and there are no tutorials - help most welcome on these.

Btw, you can bump into the same issue with Compojure, as CONTEXT recreates all the subroutes at runtime - every middleware mounted under a context is recreated on every request(!!!). I’m starting to think Middleware is too simple a concept for more complex apps: async requires an extra arity (still not supported by many libs), async error handling is hard and the mw lifecycle is entangled with chain lifecycle.

To glue all the good stuff together, we are (still) blueprinting Talvi, a simple and performant web framework for Clojure, built on top of reitit-http, supporting promises & interceptors, having an option for most of the things with a goal of providing good and coherent developer experience over everything. Currently hoarding ideas from web stacks in Elixir, Rust and Java/Scala. Lots of ideas, too little time.

1 Like