Created: 2016-12-10 Sat 08:40
yadayada is declarative(yada/resource
{:methods
{:get
{:produces "text/html"
:response
(fn [_] "Hello World!
")}
:put
{:consumes "application/json"
:parameters {:body {:greeting String}}
:response (fn [ctx] ...)}}})
yada is standards-compliantyada is linearavailable? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
(defn known-method?
[ctx]
(if-not (:method-wrapper ctx)
(d/error-deferred
(ex-info ""
{:status 501
::method (:method ctx)}))
ctx))
yada is asynchronousavailable? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
yada is extensible(extend-protocol Method
BrewMethod
(keyword-binding [_] :brew)
(safe? [_] false)
(idempotent? [_] false)
(request [_ ctx]
;; Method semantics here
))
(defmethod parse-stream
"application/transit+msgpack"
[_ stream]
(-> (bs/to-input-stream stream)
(transit/reader :msgpack)
(transit/read)
(with-400-maybe)))
yada is scaleableavailable? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
{:produces "text/html"}
becomes
{:produces
[{:media-type "text/html"}]}
{:produces
[{:media-type "text/html"
:charset "UTF-8"
:language #{"en" "zh-ch;q=0.9"}}
{:media-type "text/html"
:charset "Shift_JIS"
:encoding "gzip"
:language "zh-ch;q=0.9"}
{:media-type "text/plain"}]}
available? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
(yada/resource
{:methods
{:get
{:parameters
{:query {:foo s/Inst}
:body {:request {:intent {:name s/Str}}}}}}})
available? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
(extend-protocol yada.resource/ResourceCoercion
String
(as-resource [s]
(resource
{:properties {:last-modified (to-date (now))
:version s}
:methods
{:get
{:produces
[{:media-type "text/plain"
:charset charset/platform-charsets}]
:response (fn [ctx] s)}}})))
available? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
(yada/resource
{:id ::basic-example
:access-control
{:scheme "Basic"
:verify
(fn [[user password]]
(when (= [user password]
["scott" "tiger"])
{:user "scott"
:roles #{"secret/view"}}))
:authorization
{:methods
{:get "secret/view"}}}})
(yada/resource
{:methods
{:get {:produces "text/event-stream"
:response (chan)}}})
available? → known-method? → uri-too-long? → TRACE → method-allowed? → parse-parameters → capture-proxy-headers → authenticate → get-properties → authorize → process-content-encoding → process-request-body → check-modification-time → select-representation → if-match → if-none-match → invoke-method → get-new-properties → compute-etag → access-control-headers → security-headers → create-response → logging → return
(yada/resource
{:methods
{:get
{:response (fn [ctx] nil)}}
:responses
{404 {:response "Not found"}}})
Routes and Resources should be independent – Phillip Meier
["/phonebook" [
["" :index]
[["/" :id] :entry]
]]
/phonebook -> :index
/phonebook/123 -> :entry
:index -> /phonebook
:entry 123 -> /phonebook/123
yada is evolving
yada