Hacker News new | past | comments | ask | show | jobs | submit login
Developing and Deploying a Simple Clojure Web Application (mmcgrana.github.com)
158 points by liebke on July 24, 2010 | hide | past | favorite | 40 comments



In Common Lisp (without cheating or handwaving; this is it):

  (defpackage :add-nums
    (:use :cl :hunchentoot :cl-who))
  
  (in-package :add-nums)
  
  (defmacro with-html (&body body)
    `(with-html-output-to-string (*standard-output* nil :prologue t :indent t)
       ,@body))
  
  (define-easy-handler (add-nums :uri "/add-nums")
      ((a :parameter-type 'integer)
       (b :parameter-type 'integer))
    (with-html
      (:html
       (:head (:title "Add two numbers"))
       (:body
        (if (and a b)
          (htm (:p (str (+ a b)))))
        (:form :method :get
         (:input :type :text :name "a")
         (:input :type :text :name "b")
         (:input :type :submit))))))
  
  (defparameter *site* (make-instance 'acceptor :port 8080))
  
  (start *site*)


The equivalent Clojure code is actually a few lines shorter than your example:

    (ns add-nums
      (:use compojure.core [hiccup core page-helpers] ring.adapter.jetty))

    (defroutes handler
      (GET "/add-nums" [a b]
        (let [a (Integer/parseInt a)
              b (Integer/parseInt b)]
          (html
            [:html
              [:head [:title "Add two numbers"]]
              [:body
                (if (and a b) [:p (+ a b)])
                (form-to [:get "/add-nums"]
                  (text-field :a)
                  (text-field :b)
                  (submit-button))]])))

    (run-jetty handler {:port 8080})
Mark's tutorial code is a little more complete than your example, and doesn't aim for brevity. It also doesn't use any of the form functions from Hiccup (admittedly, they're not as well documented as they could be).


Finally, an actual programmer's response.

Thank you! It's good to know that verbosity was for the sake pedagogy and completeness, and not necessity.


But you are cheating:

* you've omitted code to control the output content-type and the associated response headers (xhtml vs html)

* you've removed text, formatting from the form page

* you've discarded the results page altogether

* you aren't properly distinguishing between GET and POST

Do the same to the clojure code and it'll be about the same length as well.


Your requests, when they're valid, are embarrassingly simple one-liners.

you've omitted code to control the output content-type and the associated response headers (xhtml vs html)

Add this single line to your WITH-HTML macro.

  (setf (html-mode) :xml)  ; for XML or :sgml for HTML.
http://weitz.de/cl-who/#html-mode

you've removed text, formatting from the form page

Add one line for a CSS file inclusion and style it to your heart's content. In real web apps I use html-template to template the code, and do not sloppily generate html like I did with the example; but I had to do what the clojure code did, in the same manner.

you've discarded the results page altogether

I am printing the results on the same page. Yeah, that's a better usability.

you aren't properly distinguishing between GET and POST

Says who? the DEFINE-EASY-HANDLER takes arguments, which correspond to the submitted form elements, via GET or POST. In fact, that macro also does some type conversion for you as well; since you declared your parameters to be integers they will be converted to integers when you get them, and not remain strings. This stuff is built into the web server.

http://weitz.de/hunchentoot/#define-easy-handler

If you're gonna implement a full REST then you have no business generating your display html from within your container.

What else do you think I omitted?


It would have been easier and no less accurate for you to write, "yes, my cl code was shorter only because I omitted a bunch of stuff." If you're going to start a dick-waving contest, at least man-up and write your code so it has the same behavior.


Wow!

First sophistry and now this .. sophistication. I think I am out of my intellectual depth here, and you will have to excuse me for bidding you an early adieu!

[Edit:

I see you have only registered a day ago, welcome aboard! But can you please be a little gentle? (specially in sentences containing a 2nd person pronoun.)


Er, Clojure has CL style macros so you can easily get to this level of brevity if that is desired.


The one custom macro I wrote is already in there. The rest is just the web server and cl-who.

I have been screaming for ages telling Clojurists to rip CL APIs and implement them in clojure. They're more tasteful and cultured than that entrerprisey crap that java is smearing all over this nice Lisp dialect.

The majority of open source clojure code that I have seen looks like Java FFI stubs; you need to tuck those loose ends in and tidy them up with macros. But this probably wont happen until Clojure is ported to another runtime/platform; portability is a surefire way to distill the essence of a language from its implementation detail.


I won't venture to saying anything about CL libs - I don't know or use them. But clearly you don't know much about the Clojure library landscape. All the ones I use are Lisp-y and delicious.


"I have been screaming for ages telling Clojurists to rip CL APIs and implement them in clojure."

Care to help? If you feel this strongly about it, surely you can contribute to the community.


For the same reason that everyone who retweeted an #iranelection did not book a flight to Tehran to fight with their comrades. I have things to do, and my immediate needs to take care of: that pretty much means Common Lisp, which I depend on for my work.

My advice is just that, advice, and it's given in the hope that with our mutual situations improved, maybe we can meet for coffee somewhere down the road and kick it back.


What's so great about the CL APIs for web applications? Could you provide some examples?


Another nice example can be found in the last "Functional Web" column on IEEE Internet Computing by Steve Vinosky: http://steve.vinoski.net/pdf/IC-Getting_Started_with_Google_...

In the July/August 2010 column, Getting Started with Google App Engine and Clojure, guest columnist Aaron Bedra shows how to use Clojure, a relatively new but robust Lisp implementation on the Java Virtual Machine, create and deploy an application using the Compojure web framework on the Google App Engine platform.


Great article, thanks for the link.

Couple more helpful links for some basics not covered in the article (all work in progress):

Compojure docs: http://www.compojure.org

Stub for "Clojure Web Development" book: https://docs.google.com/Doc?docid=0AQqGP1CDN0uIZGhmZjJmcGZfM...


This is a great tutorial. Over the past few months I've been struggling with getting a "barebones" app up and running with Clojure. Leiningen has really come into its own in 2010 and tutorials like this will be great for people who need a basic template in order to bootstrap them into the whole experience.


If this is an easy way to create a web app that adds two numbers on Clojure, I'd say Clojure is not ready for web development yet.


Huh. 45 LOC for templating, routing, and form processing and you don't need to configure a different webserver since jetty is production quality. Do you have links to something that takes less effort than what is being illustrated here that can be deployed immediately into production and perform well?


Not to mention: middlewares, logging, stack traces, exception handling, testing, production/dev environments, e.t.c. in a similarly succinct manner.


Agreed. This strikes me as a more robust walk-through than traditional Hello World-esque tutorials; as such, there is a little more to do than you'd expect. I'd rather have the details provided here, and I suspect many other hackers would too.


It's interesting. I read your comment through the "backtype version" below the article, and, because it was out of context, I interpreted your meaning to be exactly the opposite of what I see it is now.


http://pastebin.com/PsecNBvB

(To be honest, I think clojure has its purposes, but a one-off calculator page isn't one of them. Use the right tool for the right job and all that.)


What point are you trying to make? That one can write less code if one does less stuff?


The parent asked for a link to something that takes less effort, I obliged. I don't think the amount of code is a particularly useful metric in most cases, but I would argue that the PHP+HTML solution is much clearer and easier to deploy, and taking into account everything you wish about such a simple web page (readability, maintainability, cross-server, security, etc.), takes less effort in the end. (I don't have any big issues with jetty or tomcat, since I use one or the other almost daily.) I'm sure there are larger use cases where clojure is simpler than raw PHP, but that's why PHP has frameworks.


why are some people so lazy and short sighted.

"time to make trivial webapp" is NOT a good reason to choose anything.


Are you serious? 45 LOC is not a good metric btw, why are you omitting all that boilerplate configuration. Any reasonable tutorial on PHP/python/RoR would build something more sophisticated more concisely. Here is a python tutorial: http://www.turbogears.org/2.0/docs/main/ToscaWidgets/forms.h...


There are a contingent of Lisp users who really, really, really like this fgen style, for EVERYTHING. I—as someone who's worked in the industry on lots of startup-level projects—think it's only useful for small, regular snippets. There is also this false-metric effect in play; there are only 45ish lines in one file here, so it must be elegant and great amirite?

But a real webapp would have lots of templates and lots of files.

Where Clojure really shines in web development is when you mix it with cgrand's Enlive templating engine (http://github.com/cgrand/enlive), which is an amazing project with lots of active development. This approach is so cool that even a lot of the Rails and Python startup folks are starting to copy it.


I think the point of the article is to cover the absolute basics using Ring, not advocate any particular style of development. I mean the title of the blog post does say it all.

Having written a lengthy Enlive tutorial, http://github.com/swannodette/enlive-tutorial, I of course swear by it and scoff at inline html generation :D So I prefer coupling Ring+Enlive+Moustache (and tasty Aleph) myself but that would be an awful lot to cover in a single blog post now wouldn't it ;)

All in good time.


I suspect we could do it easily. Talk to me on twitter (my name here is my name on twitter) and let's see if we can hammer out an elegant way to describe that coupling.

I need the writing practice anyways.


I'd love to see a fork of adder that used Ring+Enlive+Moustache.


Your Enlive tutorial is excellent. Thank you.


Actually, it's an easy way to: - add two numbers - build the project with dependencies - display stack traces - deliver static files - generate html from code - validate user input - host with a web server - reload the web server during development - handle url routing - log requests - create custom middleware - deploy to EC2

You may have glossed over some of the details.


No, I didn't gloss over the details with the possible exception of deployment to EC2. Most of the stuff you listed are a prerequisite to web development. For most other languages/frameworks database connection would be included too.


Perhaps you meant to say that the framework used in this example is not ready. I didn't see anything about Clojure the language that makes the example complicated.

As far as the framework is concerned, the example shows how to build a production deployment of the application. The author is not showing a toy teaser application. There are a lot of details there, but these are things that you would want to know if you actually want to run a production server.


I agree with this, and yes I used the word 'clojure' to mean any frameworks/web servers/middleware that can be used to code in clojure. Just like when people say "php is good for web programming" most of them actually mean php, apache, mysql and their favorite framework.


You can thank people like Mark McGranaghan for taking languages that "aren't ready for X" yet and making them so.


That is a TON if code for such a simple fiction.


That is a ton of code if the goal is writing a web page that does addition. Maybe that wasn't the goal.


This is great information. I'd love to see a similar tutorial for NodeJS for comparison.


Clojure is cool.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: