How do you make a web application in Clojure? [closed]
Asked Answered
D

16

219

I suppose this is a strange question to the huge majority of programmers that work daily with Java. I don't. I know Java-the-language, because I worked on Java projects, but not Java-the-world. I never made a web app from scratch in Java. If I have to do it with Python, Ruby, I know where to go (Django or Rails), but if I want to make a web application in Clojure, not because I'm forced to live in a Java world, but because I like the language and I want to give it a try, what libraries and frameworks should I use?

Dreher answered 3/10, 2008 at 14:52 Comment(9)
I was wondering whether you wish to use Java Native API or Clojure Native ones ?Zenda
Ande: I'm really not sure, as I know so little about the Java world in this respect (but I've been using Java, the language, for some time at work already).Dreher
I think it would be nice if this question ended up with a list of Clojure web frameworks, one answer each, and anyone could vote their favorite. I think Meredydd's is definitely the Compojure's answer. I'll add one for Webjure and it'd be nice to have a comparison.Dreher
Pupeno! I arrived here searching for "web applications with clojure". This page was the first result in Google.Selfpossession
Look also at related question #3325533Clangor
Notepad(emacs): done. No shaving: done. Manmode: ONKelcy
@AdamArold: did you seriously compare Emacs to Notepad? Like, really??!Cineaste
Emacs is a superset of Notepad if you look at it that way (Emacs can be used in place of Notepad).Kelcy
Just offering an update on the status of Clojure web development ... check out juxt.pro/blog/posts/yada-1.html Yada. (pretty funkin' new as of Jun 2016)Vedda
K
105

By far the best Clojure web framework I have yet encountered is Compojure: http://github.com/weavejester/compojure/tree/master

It's small but powerful, and has beautifully elegant syntax. (It uses Jetty under the hood, but it hides the Servlet API from you unless you want it, which won't be often). Go look at the README at that URL, then download a snapshot and start playing.

Kanara answered 11/10, 2008 at 17:23 Comment(11)
while it's easy to include libs this way... dependency creep is not a good thing. You need balance. But this is nuts!Broddy
Was Richard's comment meant for this answer? I don't understand it.Capricorn
One of the strengths of Clojure is that it runs on the JVM and can access other libs that also run on the JVM. My concern is that this is also it's weakness... as demonstrated by Compojure and it's deep dependency with Jetty which is a java lib. Jetty is pretty a pretty good platform, however, if one of your reasons for using Clojure is something like "it's a functional language" then you lose a lot of that benefit once you start using libs not built on Clojure.Broddy
@Broddy Your argument is pretty silly. Yes, if you decide to use java libraries, you're giving up being functional in a lot of cases. But the point of these libraries is so that you never have to do it again. For example, Ring is a Clojury wrapper around servlets so you don't have to use servlets directly. Would you propose we reinvent the web development wheel from scratch rather than making the perfectly good Java tools nice to use from Clojure? Where is the logic in that. Furthermore, how is having the option of using these libraries a bad thing? ...Dogooder
@Dogooder "if you decide to use java libraries, you're giving up being functional" was exactly my point. And I do not think it's silly ... what is silly is "wrapping servlets so you don't have to use them again" When that is my point made again. In the end non-functional code is being called at every level. While I'm writing my next killer app the last thing I want to do is deconstruct every dependency to make sure it confirms or is suitable. (a much bigger topic).Broddy
Yes, my comment was meant for this answer. I was suggesting that wrapping Jetty, which is a java app, is not very functional.Broddy
@Broddy Your whole argument implies that non-functional non-Clojure code is inherently so bad that even the presence of it hidden beneath a library is a contamination. I don't understand this reasoning. A lot of Java libraries are useful and powerful pieces of code. Why rewrite those from the ground up when we can simply provide our own wrapper libraries that make it possible to use them elegantly and functionally from Clojure?Dogooder
@Richard, feel free to make a pure-clojure http server.Bevan
@Richard, this is a slightly lower-level implementation than the jetty one: github.com/datskos/ring-netty-adapterBevan
In Lisp/Clojure terms, a function has no side effects. (see gigamonkeys.com/book/…). However as pointed out in the Land of Lisp (landoflisp.com/trade_func.png), a purely functional program typically isn't very useful because side effects are necessary to actually do things, like write database records, download files, post to a REST server, generate images, etc...Legatee
@Ifalin - Einstein should probably have said, "Make programs as functional as possible - but no functionaller!".Electroscope
D
180

Compojure is no longer a complete framework for developing web applications. Since the 0.4 release, compojure has been broken off into several projects.

Ring provides the foundation by abstracting away the HTTP request and response process. Ring will parse the incoming request and generate a map containing all of the parts of the request such as uri, server-name and request-method. The application will then handle the request and based on the request generate a response. A response is represented as a map containing the following keys: status, headers, and body. So a simple application would look like:

(def app [req]
  (if (= "/home" (:uri req))
    {:status 200
     :body "<h3>Welcome Home</h3>"}
    {:status 200 
     :body "<a href='/home'>Go Home!</a>"}))

One other part of Ring is the concept of middle-ware. This is code that sits between the handler and the incoming request and/or the outgoing response. Some built in middle-ware include sessions and stacktrace. The session middle-ware will add a :session key to the request map that contains all of the session info for the user making the request. If the :session key is present in the response map, it will be stored for the next request made by the current user. While the stack trace middle-ware will capture any exceptions that occur while processing the request and generate a stack trace that is sent back as the response if any exceptions do occur.

Working directly with Ring can be tedious, so Compojure is built on top of Ring abstracting away the details. The application can now be expressed in terms of routing so you can have something like this:

(defroutes my-routes
  (GET "/" [] "<h1>Hello all!</h1>")
  (GET "/user/:id" [id] (str "<h1>Hello " id "</h1>")))

Compojure is still working with the request/response maps so you can always access them if needed:

(defroutes my-routes
  (GET "*" {uri :uri} 
           {:staus 200 :body (str "The uri of the current page is: " uri)}))

In this case the {uri :uri} part accesses the :uri key in the request map and sets uri to that value.

The last component is Hiccup which makes generating the html easier. The various html tags are represented as vectors with the first element representing the tag name and the rest being the body of the tag. "<h2>A header</h2>" becomes [:h2 "A Header"]. The attributes of a tag are in an optional map. "<a href='/login'>Log In Page</a>" becomes [:a {:href "/login"} "Log In Page"]. Here is a small example using a template to generate the html.

(defn layout [title & body]
  (html
    [:head [:title title]]
    [:body [:h1.header title] body])) 

(defn say-hello [name]
  (layout "Welcome Page" [:h3 (str "Hello " name)]))

(defn hiccup-routes
  (GET "/user/:name" [name] (say-hello name)))

Here is a link to a rough draft of some documentation currently being written by the author of compojure that you might find helpful: Compojure Doc

Distribute answered 17/7, 2010 at 15:54 Comment(0)
K
105

By far the best Clojure web framework I have yet encountered is Compojure: http://github.com/weavejester/compojure/tree/master

It's small but powerful, and has beautifully elegant syntax. (It uses Jetty under the hood, but it hides the Servlet API from you unless you want it, which won't be often). Go look at the README at that URL, then download a snapshot and start playing.

Kanara answered 11/10, 2008 at 17:23 Comment(11)
while it's easy to include libs this way... dependency creep is not a good thing. You need balance. But this is nuts!Broddy
Was Richard's comment meant for this answer? I don't understand it.Capricorn
One of the strengths of Clojure is that it runs on the JVM and can access other libs that also run on the JVM. My concern is that this is also it's weakness... as demonstrated by Compojure and it's deep dependency with Jetty which is a java lib. Jetty is pretty a pretty good platform, however, if one of your reasons for using Clojure is something like "it's a functional language" then you lose a lot of that benefit once you start using libs not built on Clojure.Broddy
@Broddy Your argument is pretty silly. Yes, if you decide to use java libraries, you're giving up being functional in a lot of cases. But the point of these libraries is so that you never have to do it again. For example, Ring is a Clojury wrapper around servlets so you don't have to use servlets directly. Would you propose we reinvent the web development wheel from scratch rather than making the perfectly good Java tools nice to use from Clojure? Where is the logic in that. Furthermore, how is having the option of using these libraries a bad thing? ...Dogooder
@Dogooder "if you decide to use java libraries, you're giving up being functional" was exactly my point. And I do not think it's silly ... what is silly is "wrapping servlets so you don't have to use them again" When that is my point made again. In the end non-functional code is being called at every level. While I'm writing my next killer app the last thing I want to do is deconstruct every dependency to make sure it confirms or is suitable. (a much bigger topic).Broddy
Yes, my comment was meant for this answer. I was suggesting that wrapping Jetty, which is a java app, is not very functional.Broddy
@Broddy Your whole argument implies that non-functional non-Clojure code is inherently so bad that even the presence of it hidden beneath a library is a contamination. I don't understand this reasoning. A lot of Java libraries are useful and powerful pieces of code. Why rewrite those from the ground up when we can simply provide our own wrapper libraries that make it possible to use them elegantly and functionally from Clojure?Dogooder
@Richard, feel free to make a pure-clojure http server.Bevan
@Richard, this is a slightly lower-level implementation than the jetty one: github.com/datskos/ring-netty-adapterBevan
In Lisp/Clojure terms, a function has no side effects. (see gigamonkeys.com/book/…). However as pointed out in the Land of Lisp (landoflisp.com/trade_func.png), a purely functional program typically isn't very useful because side effects are necessary to actually do things, like write database records, download files, post to a REST server, generate images, etc...Legatee
@Ifalin - Einstein should probably have said, "Make programs as functional as possible - but no functionaller!".Electroscope
I
49

There's also "Noir" (http://www.webnoir.org/), which is a new Clojure web framework (so new the docs aren't there yet). Coming from Django/Rails, I dig the simple, straightforward syntax and it's pretty lean.

Ironbound answered 23/6, 2011 at 5:31 Comment(3)
Webnoir is actually really useful! It's very easy to get started with - you can develop it a bit actually a bit like one seems to develop php - just start a server (this time with leiningen), edit your files and reload your browser to see what you got.Auriferous
Since @Ironbound has answered, Noir now has the docs available: webnoir.org/docsBreathless
Just for the record, it seems Noir has been deprecated and is no longer maintained....Kalila
D
25

Consider the Luminus web framework. I have no affiliation but have heard good things from friends I respect.

Duffy answered 26/11, 2014 at 20:24 Comment(0)
L
21

My current go-to web library is now yada.

If you are just starting out, the introductory server is Compojure. I see it as the apache of web servers in the Clojure world (in which case yada/aleph would be nginx). You could use Luminus as a template. There are variants of it, like compojure-api.

I tried ou Pedestal and was globally satisfied with it. I don't claim to master it, but it has a pleasant syntax, feels very cohesive, and looks like it does have great performance. It is also backed by Cognitect (the Clojure/Datomic company where Rich Hickey works).

I found Aleph to present an interesting abstraction, and the built-in backpressure seems interesting. I have yet to play with it, but it's definitely on my list.

After playing a bit with various web servers, here is my quick Pro/Cons list :

Short answer : have a look at Luminus to get started quickly, maybe move on to something else as your needs evolve (Yada maybe).

Compojure

  • Pros (1):

    • easy, lots of templates/examples (ex. Luminous)
  • Cons (2):

    • Not performant (a thread per request), expect performances slightly better than rails
    • Not simple, the middleware model has inconvenients

Pedestal

  • Pros (3):

    • interceptor model, pleasant syntax to add interceptors to a subset of routes
    • performant router
    • supports json/transit/multipart forms transparently out of the box, without asking anything. Very cool !
  • Cons (4):

    • no websocket support (yet), returning core.async channels would be nice
    • a bit slow to reload if putting it in a Stuart Sierra's component (I think you are supposed to use the reload interceptor)
    • no testing facility for async interceptors
    • requires buy-in (?)

Aleph

Pro (3):

  • Performant
  • backpressure
  • Websocket/SSE support when returning a manifold stream

Cons (1):

  • Low level, do it yourself style (ie. it just gives you a way to make your handlers do something. No router, no nothing). Not really a cons, just be aware of it.

Yada

Pro (3):

  • built on Aleph
  • content negociation
  • swagger integration
  • bidi is quite ok (though I like pedestal router syntax better)

Cons (1):

  • documentation (although not as bad as nginx-clojure, quickly improving).

HttpKit

Pro (2):

  • Written in Clojure ! (and Java...)
  • performance looks good (see the 600K concurrent connections post)

Cons (2):

  • No CORS support
  • Bugs ? Also, not a lot of recent commits

Nginx-Clojure

Note : I haven't played with it, mainly because of the lack of documentation. It looks interesting though, and very performant.

Pros (2):

  • Nginx (performant, offload ssl, restart workers...)
  • Could this model allow zero-downtime updates ? That would be so awesome !

Cons (1):

  • Documentation (improving). Also, I don't want to program in strings embedded in an nginx config file if that is the only way to do it.
  • Probably complicates a bit the first deployment (?)

Immutant

Note : I haven't played with it.

Pros :

  • integrated (caching, messaging, scheduling, wildfly deploy)

Cons :

  • no http client

Catacumba

Note : I haven't played with it, although the documentation looks excellent. I am probably going to try it next. There are example chat projects that look interesting, their heavy use of protocols put me off at first as a novice Clojure dev.

Pros (6):

  • documentation ! Like all funcool projects, the doc is very pleasant to read.
  • pedestal-like routing syntax
  • should be performant (on top of Ratpack)
  • backpressure
  • websockets, sse, cors, security, ssl...
  • unique features to dig : postal

Cons (2):

  • Not completely sure about how pleasant the ct/routes syntax is, and about ditching the Ring spec (supposedly for the async story, but I thought the pedestal guys fixed that)
  • Not sure how one would integrate swagger etc.
  • when I tried it, I was not able to make it work straight away

Note : a benchmark of Clojure web servers is available, if raw performance is all that matters.

Listed answered 23/8, 2015 at 10:27 Comment(2)
Great comparison. not sure how the nginx metaphor works though :)Singlehanded
@matanster I see apache as the default go-to server for a lot of organisations. Simple, works for many. But it is older than nginx too, and uses a different internal model. Compojure is synchronous (that may change) while Yada is asynchronous. Another benefit of Yada I did not mention is that everything is data, so it is much easier to compose/transform/inspect/generate compared to macros like in Compojure.Listed
A
14

These days Pedestal is a framework worth a look. It's a server-side framework that builds on top of Ring, but also frees the incoming request from the initial thread by being able to pause and resume that particular request (otherwise a slow request actually block that serverthread). Maybe sort of like a JavaBean.

Other cool frameworks are hoplon.io and David Nolen's Om (based on React)

Auriferous answered 13/8, 2013 at 8:53 Comment(0)
D
11

Webjure, a web programming framework for Clojure.

Features: Dispatch servlet calls Clojure functions. Dynamic HTML generation. SQL query interface (through JDBC).

This answer is meant as a placeholder for Webjure information.

Dreher answered 20/10, 2008 at 5:51 Comment(1)
I'm not sure this is a good example either. While the codebase seems shallow(good) there is enough written in java that it seems to miss the mark. I would have expected a pure clojure framework.Broddy
S
8

Compojure's what I used to build a tiny blogging application. It's modeled on Sinatra, which is a minimal, light-weight web framework for Ruby. I mostly just used the routing, which is just like Sinatra's. It looks like:

(GET "/post/:id/:slug"
  (some-function-that-returns-html :id :slug))

There's no ORM or templating library, but it does have functions that turn vectors into HTML.

Sibling answered 4/3, 2009 at 13:42 Comment(0)
Q
5

You can also have look at these frameworks (taken from disclojure/projects):

There is also one more related question on Stack Overflow: Mature Clojure web frameworks?

Quinquereme answered 21/5, 2011 at 9:2 Comment(1)
Twister is written in Go language, not Clojure.Baines
D
3

Disclaimer: I am the author.

I put together a leiningen template which combines luminusweb and chestnut templates. So you get something that you can build clojure code with and clojurescript code for front and backend.
Additionally it provides user management plus some simple CRUD generation and some more small nice to haves: https://github.com/sveri/closp

Downturn answered 28/4, 2015 at 11:17 Comment(0)
Y
3

I'll throw in my two cents for Duct, also from @weavejester, the maintainer of Compojure and Ring.

At it's core, it brings Component and the Ring router under one roof. Reasons why I use Duct:

  • Excellent philosophical foundation: it encourages you to build your app as a series of small components, and it strikes a nice balance between holding few opinions while providing sane defaults.
  • Stable path: I speak for myself, but over the years I've felt that the Clojure community has presented one less-than-credible web framework after another. A couple simply felt too experimental (my experience with Om and client-side Pedestal) for "getting things done" (not that they won't prove superior down the road). On the other hand, I feel like @weavejester has brought the same stability and measured progress to Duct that he did to Compojure and Ring, which have been superbly born out in the community.
  • It's super lightweight, and out of the way of my components.

Major features:

  • Organizes routes by "endpoints", small components that can you can think of as mini web servers (or, small cross sections of your HTTP routes).
  • Out-of-the-box support for the Reloaded Workflow.
  • Perfect integration with Ring and Compojure.
  • Development and production configurations (something I've found conspicuously missing elsewhere).
  • Good documentation with examples.

Note: It goes without saying, but for the benefit of web development newcomers, like most Clojurey things Duct requires a solid grasp of Clojure the language. I also recommend reading about Component first.

On another personal note, I've been using Duct in several production applications for over a year now and am extremely happy with it.

Yardarm answered 5/10, 2016 at 23:6 Comment(0)
M
2

you can also try Clojure on Coils, http://github.com/zubairq/coils - disclaimer: I am the author

Module answered 14/8, 2013 at 12:32 Comment(0)
A
2

Another interesting webserver is Http-kit. It has good performance and is ring compliant, and has support for WebSockets as well. It is made mostly in clojure, and lacks some of the strange things in Jetty/Tomcat.

It's easy to tinker with.

Auriferous answered 20/5, 2015 at 14:24 Comment(0)
R
2

Reframe and om.next probably what you are looking for.

Racial answered 22/12, 2016 at 8:4 Comment(0)
V
1

Arachne is a newcomer web framework. Quoting the site's description:

Arachne is a full, highly modular web development framework for Clojure. It emphasizes ease, simplicity, and a solid, scalable design.

It has a kickstarter campaign claiming to offer a "getting started" experience similar to Rails. It is developed by a Cognitect.

Here is a good discussion about it with the author of Luminus (yogthos).

Vampire answered 19/2, 2017 at 20:28 Comment(0)
T
1

I've been using Liberator successfully in production for a while now. It's a great framework if you want just the bare bones e.g. if you're building a RESTful web service or something similar. It's essentially a wrapper for ring and compojure and provides a decision graph when validating incoming requests. It's also extremely fast compared to other more bulky web frameworks. If you want to start somewhere fast and slowly build out then Liberator is a great choice.

Te answered 4/5, 2017 at 14:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.