Getting Started

hype provides a number of functions to assist in using hypermedia in APIs. Primarily, hype uses reverse routing to build URLs and paths. Currently, hype expects ring compatible requests and provides support for the bidi routing library but could be extended to support others in the future.

hype can build absolute paths (i.e., paths that start from /) and absolute URLs (i.e., including scheme and host) and provides some facilities for converting between the two.

hype can build URLs and paths including any or all of:

Requiring hype

hype can be required with:

(require '[hype.core :as hype])

Generating paths

Given a set of bidi routes:

(def routes 
  [""
   [["/" :index]
    ["/articles" :articles]
    [["/articles/" :article-id] 
     [["" :article]
      [["/sections/" :article-section-id] :article-section]]]]])

an absolute path, say for :articles, can be generated as follows:

(hype/absolute-path-for routes :articles)
; => "/articles"

If the route requires a path parameter, such as in the :article route above:

(hype/absolute-path-for routes :article
  {:path-params {:article-id 26}})
; => "/articles/26"

To leave the path parameter templated for use in URI templates:

(hype/absolute-path-for routes :article
  {:path-template-params {:article-id :article-id}})
; => "/articles/{articleId}"

Path template parameters are automatically converted to camel case. This behaviour can be overridden as follows:

(hype/absolute-path-for routes :article
  {:path-template-params {:article-id :articleID}
   :path-template-param-key-fn clojure.core/identity})
; => "/articles/{articleID}"

If the route requires multiple path parameters, such as in the :article-section route above:

(hype/absolute-path-for routes :article-section
  {:path-params {:article-id 26
                 :article-section-id 1}})
; => "/articles/26/sections/1

Query parameters are also supported when generating a path:

(hype/absolute-path-for routes :articles
  {:query-params {:page 2
                  :per-page 10}})
; => "/articles?page=2&perPage=10"

As for path template parameters, query parameter keys are automatically converted to camel case. This behaviour can be overridden as follows:

(hype/absolute-path-for routes :articles
  {:query-params {:page 2
                  :per-page 10}
   :query-param-key-fn clojure.core/identity})
; => "/articles?page=2&per-page=10"

Both path and query parameters can be provided together:

(hype/absolute-path-for routes :article
  {:path-params {:article-id 26}
   :query-params {:include-all-sections true}})
; => "/articles/26?includeAllSections=true"

When paths need to include query string template parameters:

(hype/absolute-path-for routes :articles
  {:query-template-params [:page :per-page]})
; => "/articles{?page,perPage}"

Again, query template parameter keys are converted to camel case by default. This behaviour can be overridden as follows:

(hype/absolute-path-for routes :articles
  {:query-template-params [:page :per-page]
   :query-template-param-key-fn clojure.core/identity})
; => "/articles{?page,per-page}"

Query string template parameters can be used in addition to path parameters and other query string parameters:

(hype/absolute-path-for routes :article
  {:path-params {:article-id 26}
   :query-params {:include-all-sections true}
   :query-template-params [:include-summary]})
; => "/articles/26?includeAllSections=true{&includeSummary}"

Currently, there is no support for relative paths.

Generating URLs

Given the set of routes defined in Generating paths and a ring request such as that produced by:

(require '[ring.mock.request :as ring-mock])

(def request (ring-mock/request "GET" "https://localhost:8080/help"))

an absolute URL, say for :articles, can be generated as:

(hype/absolute-url-for request routes :articles)
; => "https://localhost:8080/articles"

All parameters that can be passed to absolute-path-for can also be passed to absolute-url-for, for example:

(hype/absolute-url-for request routes :article
  {:path-params {:article-id 26}})
; => "https://localhost:8080/articles/26"

(hype/absolute-url-for request routes :article
  {:path-template-params {:article-id :articleID}
   :path-template-param-key-fn clojure.core/identity})
; => "https://localhost:8080/articles/{articleID}"

(hype/absolute-url-for request routes :articles
  {:query-template-params [:page :per-page]})
; => "https://localhost:8080/articles{?page,perPage}"

(hype/absolute-url-for request routes :article
  {:path-params {:article-id 26}
   :query-params {:include-all-sections true}
   :query-template-params [:include-summary]})
; => "https://localhost:8080/articles/26?includeAllSections=true{&includeSummary}"

Converting between paths and URLs

Given the request defined in Generating URLs and an absolute path, such as:

(def absolute-path "/articles/26/sections/3")

an absolute URL relative to the request can be generated as:

(hype/absolute-path->absolute-url request absolute-path)
; => "https://localhost:8080/articles/26/sections/3"