Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Liberator Free your data with RFC 2616

Liberator Free your data with RFC 2616

The slides for talk about liberator I gave at euroclojure 2013. As I prepared this for a conference it contains not all of the information because it's missing to oral part.

You can access the demo project here:

https://github.com/ordnungswidrig/liberator-presentation

Philipp Meier

October 14, 2013
Tweet

More Decks by Philipp Meier

Other Decks in Programming

Transcript

  1. Liberator Free your data with RFC 2616 Liberator Free your

    data with RFC 2616 Philipp Meier Software Developer http://philipp.meier.name/ @ordnungswprog euroclojure 2013 berlin http://www.fickr.com/photos/aidanmorgan/3352417491/
  2. What is HTTP? • Request and response • Headers and

    body • Methods • Status codes • Content negotiation • Conditional request • And more... • Request and response • Headers and body • Methods • Status codes • Content negotiation • Conditional request • And more...
  3. HTTP Methods 8 RFC 2616 GET, PUT, POST, DELETE, HEAD,

    OPTIONS, TRACE, CONNECT Methods 8 RFC 2616 GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, CONNECT
  4. HTTP Methods 8 RFC 2616 GET, PUT, POST, DELETE, HEAD,

    OPTIONS, TRACE, CONNECT Methods 8 RFC 2616 GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, CONNECT
  5. HTTP Methods 8+1+7 RFC 2616 PATCH (RFC 5789) WEBDAV (RFC

    4918) Methods 8+1+7 RFC 2616 PATCH (RFC 5789) WEBDAV (RFC 4918)
  6. HTTP Status codes 41+1 (RFC 2616) WEBDAV (RFC 5842) Status

    codes 41+1 (RFC 2616) WEBDAV (RFC 5842)
  7. HTTP Status codes 41+1+1 (RFC 2616) WEBDAV (RFC 5842) HTCPCP

    (RFC 2324) Status codes 41+1+1 (RFC 2616) WEBDAV (RFC 5842) HTCPCP (RFC 2324)
  8. HTTP Status codes 41+1+1 (RFC 2616) WEBDAV (RFC 5842) HTCPCP

    (RFC 2324) Status codes 41+1+1 (RFC 2616) WEBDAV (RFC 5842) HTCPCP (RFC 2324) I‘m a Teapot
  9. HTTP Status codes (< 41 26) Maximum of decisions Still

    40 branching points Status codes (< 41 26) Maximum of decisions Still 40 branching points
  10. Ring (fn [req] (cond … {:status 503} … {:status 501}

    … {:status 403} … {:status 405} …)) (fn [req] (cond … {:status 503} … {:status 501} … {:status 403} … {:status 405} …))
  11. Ring (fn [req] (cond ? {:status 503} … {:status 501}

    … {:status 403} … {:status 405} …)) (fn [req] (cond ? {:status 503} … {:status 501} … {:status 403} … {:status 405} …))
  12. Ring (fn [req] (cond ? {:status 503} ? {:status 501}

    … {:status 403} … {:status 405} …)) (fn [req] (cond ? {:status 503} ? {:status 501} … {:status 403} … {:status 405} …))
  13. Ring (fn [req] (cond ? {:status 503} ? {:status 501}

    ? {:status 403} ? {:status 405} …)) (fn [req] (cond ? {:status 503} ? {:status 501} ? {:status 403} ? {:status 405} …))
  14. Ring (defn handler [request] {:status 200 :headers {"Content-Type" "text/html"} :body

    "a event"}) (defn handler [request] {:status 200 :headers {"Content-Type" "text/html"} :body "a event"})
  15. Ring (defn handler [{m :request-method {id "id"} :params}] (if (=

    :get m) {:status 200 :headers {"Content-Type" "text/plain; charset=UTF-8"} :body (pr-str (find-session id))} {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params}] (if (= :get m) {:status 200 :headers {"Content-Type" "text/plain; charset=UTF-8"} :body (pr-str (find-session id))} {:status 405 :body "Method not allowed."}))
  16. Ring (defn handler [{m :request-method {id "id"} :params}] (if (=

    :get m) (if-let [e (find-session id)] {:status 200 :headers {"Content-Type" "text/plain; charset=UTF-8"} :body (pr-str (find-session id))} {:status 404 :body "Not found."}) {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params}] (if (= :get m) (if-let [e (find-session id)] {:status 200 :headers {"Content-Type" "text/plain; charset=UTF-8"} :body (pr-str (find-session id))} {:status 404 :body "Not found."}) {:status 405 :body "Method not allowed."}))
  17. Ring (defn handler [{m :request-method {id "id"} :params {accept "accept"}

    :headers}] (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (condp = mt "application/clojure" {:status 200 :headers {"Content-Type" "application/clojure; charset=UTF-8"} :body (pr-str e)} "text/html" {:status 200 :headers {"Content-Type" "text/html; charset=UTF-8"} :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 505 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params {accept "accept"} :headers}] (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (condp = mt "application/clojure" {:status 200 :headers {"Content-Type" "application/clojure; charset=UTF-8"} :body (pr-str e)} "text/html" {:status 200 :headers {"Content-Type" "text/html; charset=UTF-8"} :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 505 :body "Method not allowed."}))
  18. Ring (defn handler [{m :request-method {id "id"} :params {accept "accept"

    ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params {accept "accept" ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."}))
  19. Ring (defn handler [{m :request-method {id "id"} :params {accept "accept"

    ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params {accept "accept" ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."}))
  20. Ring (defn handler [{m :request-method {id "id"} :params {accept "accept"

    ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params {accept "accept" ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."}))
  21. (defn handler [{m :request-method {id "id"} :params {accept "accept" ims

    "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params {accept "accept" ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."})) Are these the fres of Morder?
  22. Liberator (defresource event :available-media-types ["text/html" "application/json" "application/edn"] :exists? (fn [{{{id

    "id"} :params} :request}] (if-let [talk (find-talk id)] {::talk talk})) :handle-ok ::talk :last-modified (fn [_] (begin-of-last-minute)) :etag (fn [{{{id "id"} :params} :request}] (apply str (reverse (str id id))))) (defresource event :available-media-types ["text/html" "application/json" "application/edn"] :exists? (fn [{{{id "id"} :params} :request}] (if-let [talk (find-talk id)] {::talk talk})) :handle-ok ::talk :last-modified (fn [_] (begin-of-last-minute)) :etag (fn [{{{id "id"} :params} :request}] (apply str (reverse (str id id)))))
  23. Remember? (defn handler [{m :request-method {id "id"} :params {accept "accept"

    ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."})) (defn handler [{m :request-method {id "id"} :params {accept "accept" ims "if-modified-since"} :headers}] (if (#{:get :post :put :delete :head :options :trace} m) (if (= :get m) (if-let [e (find-session id)] (if-let [mt (some #(when (or (nil? accept) (= accept "*/*") (.contains accept %)) %) ["application/clojure" "text/html"])] (let [last-modified (begin-of-last-minute) cache-headers {"Last-Modified" (.format (http-date-format) last-modified) "Vary" "Accept"}] (if (and ims (let [imsd (.parse (http-date-format) ims)] (= last-modified imsd))) {:status 304 :headers cache-headers} (condp = mt "application/clojure" {:status 200 :headers (assoc cache-headers "Content-Type" "application/clojure; charset=UTF-8") :body (pr-str e)} "text/html" {:status 200 :headers (assoc cache-headers "Content-Type" "text/html; charset=UTF-8") :body (apply format "<html><h1>%s</h1><p>%s</p><p><small>%s</small></p></html>" ((juxt :title :time :speaker) e)) }))) {:status 406 :body "Requested media type not acceptable."}) {:status 404 :body "Not found."}) {:status 501 :body "Not implemented."}) {:status 405 :body "Method not allowed."}))
  24. Liberator (defresource event :available-media-types ["text/html" "application/json" "application/edn"] :exists? (fn [{{{id

    "id"} :params} :request}] (if-let [talk (find-talk id)] {::talk talk})) :handle-ok ::talk :last-modified (fn [_] (begin-of-last-minute)) :etag (fn [{{{id "id"} :params} :request}] (apply str (reverse (str id id))))) (defresource event :available-media-types ["text/html" "application/json" "application/edn"] :exists? (fn [{{{id "id"} :params} :request}] (if-let [talk (find-talk id)] {::talk talk})) :handle-ok ::talk :last-modified (fn [_] (begin-of-last-minute)) :etag (fn [{{{id "id"} :params} :request}] (apply str (reverse (str id id)))))
  25. Liberator (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx]

    …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …)) (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx] …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …))
  26. Liberator (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx]

    …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …)) (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx] …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …))
  27. Liberator (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx]

    …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …)) (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx] …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …)) Essential Complexity Essential Complexity
  28. Liberator (defresource event :available-media-types ["text/html" "application/json" "application/edn"] :exists? (fn [{{{id

    "id"} :params} :request}] (if-let [talk (find-talk id)] {::talk talk})) :handle-ok ::talk :last-modified (fn [_] (begin-of-last-minute)) :etag (fn [{{{id "id"} :params} :request}] (apply str (reverse (str id id))))) (defresource event :available-media-types ["text/html" "application/json" "application/edn"] :exists? (fn [{{{id "id"} :params} :request}] (if-let [talk (find-talk id)] {::talk talk})) :handle-ok ::talk :last-modified (fn [_] (begin-of-last-minute)) :etag (fn [{{{id "id"} :params} :request}] (apply str (reverse (str id id)))))
  29. Context (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx]

    …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …)) (defresource event :available-media-types (fn [ctx] …) :exists? (fn [ctx] …) :handle-ok (fn [ctx] …) :last-modified (fn [ctx] …) :etag (fn [ctx] …))
  30. Context {:resource {:availabe-media-types […] :exists? … :handle-ok … ...}} {:resource

    {:availabe-media-types […] :exists? … :handle-ok … ...}}
  31. Context {:resource {:availabe-media-types […] :exists? … :handle-ok … ...}} {:resource

    {:availabe-media-types […] :exists? … :handle-ok … ...}}
  32. Context {:request {:request-method :get :params …}} ::talk {:speaker „Philipp Meier“…}}

    {:request {:request-method :get :params …}} ::talk {:speaker „Philipp Meier“…}}
  33. Context {:request {:request-method :get :params …}} ::talk {:speaker „Philipp Meier“…}

    :representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}} {:request {:request-method :get :params …}} ::talk {:speaker „Philipp Meier“…} :representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}}
  34. Context {:request {:request-method :get :params …}} ::talk {:speaker „Philipp Meier“…}

    :representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}} {:request {:request-method :get :params …}} ::talk {:speaker „Philipp Meier“…} :representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}}
  35. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  36. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  37. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  38. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  39. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  40. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  41. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} {:media-type

    „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“}
  42. Representation {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} (defprotocol

    Representation (as-response [x ctx]) {:media-type „application/edn“ :language „de“ :charset „UTF-8“ :encoding „deflate“} (defprotocol Representation (as-response [x ctx])
  43. Representation (defprotocol Representation (as-response [x ctx]) String File InputStream map

    Seq (defprotocol Representation (as-response [x ctx]) String File InputStream map Seq
  44. Representation (defprotocol Representation (as-response [x ctx]) String File {:body x}

    InputStream map Seq (defprotocol Representation (as-response [x ctx]) String File {:body x} InputStream map Seq
  45. Representation (defprotocol Representation (as-response [x ctx]) String File InputStream map

    seq (defprotocol Representation (as-response [x ctx]) String File InputStream map seq
  46. Representation seq (defmulti render-seq-generic (fn [data context] (get-in contex [:representation

    :media-type]))) seq (defmulti render-seq-generic (fn [data context] (get-in contex [:representation :media-type])))
  47. Representation map (defmulti render-map-generic (fn [data context] (get-in contex [:representation

    :media-type]))) map (defmulti render-map-generic (fn [data context] (get-in contex [:representation :media-type])))
  48. Representation map (defmulti render-map-generic (fn [data context] (get-in contex [:representation

    :media-type]))) (defmethod render-seq-generic "application/json" [data _] (json/write-str data)) map (defmulti render-map-generic (fn [data context] (get-in contex [:representation :media-type]))) (defmethod render-seq-generic "application/json" [data _] (json/write-str data))
  49. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo)))
  50. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo)))
  51. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo)))
  52. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) ;; string foo))) (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) ;; string foo)))
  53. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo)))
  54. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) ;; clojure data (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) ;; clojure data
  55. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) ;; clojure data → as-response (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok (fn [{{type :media-type} :representation foo ::foo}] (when (= „foo/bar“ type (str „my foo is „ (:green foo)) foo))) ;; clojure data → as-response
  56. Representation (defmethod render-map-generic "foo/bar" [foo _] (str „my foo is

    „ (:color foo)) (defmethod render-map-generic "foo/bar" [foo _] (str „my foo is „ (:color foo))
  57. Representation (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo

    {:color :green}}) :handle-ok ::foo) (defresource custom-representation :available-media-types [„application/json“ „foo/bar“] :exists? (fn [_] {::foo {:color :green}}) :handle-ok ::foo)
  58. POST :exists? :existed? :respond-with-entity? :new? :post-redirect? :can-post-to-missing? :processable? :post! :handle-ok

    :handle-created :exists? :existed? :respond-with-entity? :new? :post-redirect? :can-post-to-missing? :processable? :post! :handle-ok :handle-created
  59. POST :exists? :not-found :existed? :gone :respond-with-entity? :no-content :new? :created :post-redirect?

    :see-other :can-post-to-missing? :not-found :processable? 422 :post! side-effect! :handle-ok :handle-created :exists? :not-found :existed? :gone :respond-with-entity? :no-content :new? :created :post-redirect? :see-other :can-post-to-missing? :not-found :processable? 422 :post! side-effect! :handle-ok :handle-created
  60. POST :exists? :not-found :existed? :gone :respond-with-entity? :no-content :new? :created :post-redirect?

    :see-other :can-post-to-missing? :not-found :processable? 422 :post! side-effect! :handle-ok :handle-created ... :exists? :not-found :existed? :gone :respond-with-entity? :no-content :new? :created :post-redirect? :see-other :can-post-to-missing? :not-found :processable? 422 :post! side-effect! :handle-ok :handle-created ...
  61. PUT :exists? :not-found :existed? :gone :respond-with-entity? :no-content :new? :created :can-put-to-missing?

    :not-found :conflict? :conflict :processable? 422 :put! side-effect! :handle-ok :handle-created ... :exists? :not-found :existed? :gone :respond-with-entity? :no-content :new? :created :can-put-to-missing? :not-found :conflict? :conflict :processable? 422 :put! side-effect! :handle-ok :handle-created ...
  62. Integration (defresource foo… ) (→ foo wrap-dosync wrap-keyword-params wrap-params (wrap-trace

    :ui) wrap-stacktrace) (defresource foo… ) (→ foo wrap-dosync wrap-keyword-params wrap-params (wrap-trace :ui) wrap-stacktrace)