Web Apps on a Pedestal

Web Apps on a Pedestal

Learn how to build web applications in Clojure using the Pedestal library.



Ryan Neufeld

April 17, 2014


  1. Web Apps on a Pedestal

  2. @rkneufeld – rkn.io Ryan Neufeld

  3. None
  4. None
  5. Pedestal > Ring

  6. Nailed Down

  7. Flying Free

  8. Enter the workshop

  9. Todo-it

  10. Demo project-building time

  11. [“/hello” {:get hello-world}] ! Handler map Path pattern Anatomy Lesson:

  12. [“/hello” {:get hello-world} child-routes…] Anatomy Lesson: Children [“/“ [“/hello” {:get

  13. [[[“/“ [“/hello” {:get hello-world}]]]] Why so nested?

  14. [[context routes…]] ! “hello” route App name, port, host Anatomy

    Lesson: Context
  15. [[:public “example.com” routes…] [:api “api.example.com” routes…]] Anatomy Lesson: Contexts

  16. Demo project-building time part ii

  17. Exercise #1 1. Install Leiningen (http:/ /leiningen.org/#install) 2. git clone

    https:/ /github.com/rkneufeld/pedestal-workshop 3. Checkout exercise-1 4. Run the app w/ lein run 5. Visit localhost:8080/hello 6. Change “Hello, World!” to “Hello, <your name>!”* *You’ll need to restart the server
  18. Demo routes & interceptors

  19. No Handler is an Island

  20. It takes a village* *Of middleware and handlers OK, doesn’t

    have the same ring to it… Enter from left to right Leave from right to left
  21. Anatomy Lesson: Interceptors

  22. Anatomy Lesson: Interceptors

  23. Anatomy Lesson: Interceptors

  24. Routers are Interceptors

  25. Where they live (def service {::http/interceptors [… (router routes)]…} Before

    or after routing
  26. [[[“/” ^:interceptors […] [“/hello” {:get hello-world] [“/goodbye” …]]] Where they

    live Inside routes
  27. [[[“/“ [“/hello” {:get hello-world] [“/goodbye” …]]] Where they live Inside

    routes * * *Attachment points *
  28. Demo routes & interceptors

  29. Exercise #2 1. Checkout exercise-2 2. Restart your server w/

    lein run 3. Visit localhost:8080/hello?name=<yours name> 4. Use the (or x y) form to provide "World" as a default name if none is provided. 5. Bonus: Write a defon-response interceptor that changes :header’s "Server" key to something unique of your choosing.
  30. A little persistence

  31. A little persistence

  32. MVC* CRUD

  33. MVC* CRUD

  34. Demo A lil’ persistence

  35. Exercise #4 1. Checkout exercise-4 2. Launch a REPL w/

    lein repl 3. Require and enter todoit.todo.db • (require 'todoit.todo.db) • (in-ns 'todoit.todo.db) 4. Create, Read, Update, then Destroy a TODO • Get a db value with (d/db conn) 5. Bonus: Write a query completed-todos that ensures [?id :todo/completed? true]
  36. Demo Wiring up C & R

  37. Exercise #5 1. Checkout exercise-5 2. Try out /todos 3.

    Implement and wire-up a create function in todo.clj Hint: Use let à la hello-world to extract [:form-params “title”] and [:form-params “description”]. Once you’ve created a TODO, redirect to (url-for :todos).
  38. New Paint Job

  39. Demo New Paint Job

  40. Hiccup [:tag {attributes} children] required optional optional .class #id optional

  41. Hiccup <h1>The Title</h1> ! <div class=“foo”> <p>Great content</p> </div> !

    <form action=“/todos” method=“post”> <input name=“title” /> </form> [:h1 “The Title”] ! [:div.foo [:p “Great Content”]] ! ! [:form {:action “/todos” :method “post”} [:input {:name “title”}]
  42. Demo New Paint Job

  43. Exercise #6 1. Checkout exercise-6 2. Try out the new

    /todos 3. Add a TODO without a title. Oops! 4. Modify the TODO form’s title to be required (hint, the required attribute).
  44. Demo Update & Destroy

  45. Exercise #7 1. Checkout exercise-7 2. Try out toggling and

    deleting TODOs 3. Create a delete-all action. You’ll need a: • Route, • Handler, • Model Action, and • Form
  46. Questions? bit.ly/pedestal-ws @rkneufeld Photo credits: https:/ /flic.kr/p/bE6KtD, https:/ /flic.kr/p/9p4utz pedestal.io