Requests are Ring requests, expanded with information and context as it progresses through the processing stages.
{:ring.request/method :get
:ring.request/path "/index.html"
::site.resource …
::pass.authorization …}
Rather than create a new 'context' map, a Ring request map is expanded. To avoid
keyword collisions, the
Ring 2.0 namespaced
keywords are used. The ::site.handler/wrap-ring-1-adapter
wrapper function
adapts incoming and outgoing non-namespaced Ring request and response maps to
their Ring 2.0 equivalents. This function acts as an adapter that may be removed
when used with a Ring 2.0 compatible server.
A benefit of using a single request map throughout the processing stages is that all information is centralised in this single map. This helps with error handling, since any error handler has all possible information about the request for diagnostic purposes.
In Site, Web resources are XT entities.
Since a resource is identified by a URI, we use its URI (or at least its path) to identify the XT entity too.
{:xt/id "https://my.site/hello"}
The resource’s state is stored in the XT entity’s attributes, or in other XT entities it may reference.
{:xt/id "https://my.site/hello"
:message-today "Hello World!"}
The resource usually has some extra special attributes, defined by our spin library, which provide the resource’s configuration, such as the methods allowed on the resource.
{:xt/id "https://my.site/hello"
:message-today "Hello World!"
:juxt.spin.alpha/methods #{:get :head :options}}
Tip
|
If you want to learn more about resources, see Section 2 of RFC 7231. |
Representations are Clojure maps. You can either store these as XT entities too (for example, if the current representations are likely to change often). But usually, you can store them with the resource’s XT entity, shown in Hello World.
This resource has just one plain-text representation. On this occasion, given this is a static resource which remains constant, we’ve chosen to generate its payload ahead-of-time.
(alias 'http (create-ns 'juxt.http.alpha))
{:xt/id "https://my.site/hello"
:message-today "Hello World!"
::http/methods #{:get :head :options}
::http/representations
[{::http/content-type "text/plain"
::http/content-language "en"
::http/content "Hello World!\r\n"
::http/content-length 14}]}
At this stage, don’t worry that in the example, the ::http/content
value seems to
duplicate the :message-today
value in the resource. If we want to allow the
resource’s state to change, we can then generate the representation’s data from
the resource’s state on each web request. The key thing to remember is that
resources and representations are separate things.
Tip
|
If you want to learn more about representations, see Section 3 of RFC 7231. |
The web-layer is supported by some of our modern web libraries:
-
spin — A set of supporting functions to model web resources and representations as normal Clojure maps, supporting the REST architectural style. You can learn more by reading our guide to building RESTful Web APIs.
-
pick — A library to negotiate the most acceptable representation, if there is more than once to choose from.
-
reap — A low-level codec library for HTTP headers.
The OpenAPI features are supported by some additional libraries:
-
jinx — A library for JSON Schema validation and coercion in Clojure and ClojureScript.