Skip to content

Latest commit

 

History

History
323 lines (252 loc) · 10.9 KB

Resources.adoc

File metadata and controls

323 lines (252 loc) · 10.9 KB

Resources

Site maps the XTDB entity onto the concept of a web resource, as defined in REST.

We can understand why XTDB entities make for good web resources, by reading the following quote from Roy Fielding’s seminal paper introducing REST cite:[rest] (replacing Fielding’s uses of the word 'entity for 'XTDB document).

The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today’s weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author’s hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.

More precisely, a resource R is a temporally varying membership function MR(t), which for time t maps to a set of entities, or values, which are equivalent. The values in the set may be resource representations and/or resource identifiers.

— Roy Fielding

The mapping from an XTDB entity to a web resource is accomplished by the following:

  • Each XTDB entity’s :xt/id attribute is set to a URL (string), identifying the resource.

  • Representation metadata is encoded into document attributes.

A cat, viewable in a web browser. shows a document that (currently) has a single representation, of HTML.

Example 1. A cat, viewable in a web browser.
{:xt/id "https://example.org/cats/arya"
 :juxt.http.alpha/content-type "text/html;charset=utf-8" (1)
 :petshop/name "Arya"
 :petshop/species "cat"
 :petshop/color "black"
 :petshop/favorite-activity "playing with string"}
  1. This attribute declares that the resource is representable as HTML.

Site provides access to these resources via the HTTP protocol cite:[rfc7231], including support for:

  • content-negotiation

  • method semantics

  • response codes

  • conditional requests

  • range requests

  • authentication

Resources in Site are web resources, as per RFC 7231.

Resources are identified by a URI. When resources are stored in XTDB, the resource’s URI is the :xt/id attribute.

A web resource is a series of states across time, just like an XTDB entity.

In this section we’ll create a basic plain-text public resource containing the classic greeting.

Document structure of a Site resource

In Site, every XTDB document represents a resource. This means that the terms resource and document are somewhat synonymous in Site documentation.

In the same way every resource has a Uniform Resource Identitier (URI), every document in the XTDB database has an XTDB (:xt/id) identifier.

In this way, exposing data to the web is trivial. There is no convoluted logic or mappings, it’s a simple one-to-one correspondence. All Site does is provide the protocol layer to handle HTTP requests.

Site uses the request URI to lookup the corresponding XT document, and uses certain known attributes of the document to determine the web resource’s configuration and state. This mapping is illustrated in HTTP protocol mappings to XTDB document attributes. The values of these attributes determine the corresponding status, headers and body of the protocol response.

Note

Beyond the :xt/id id attribute, the attribute keywords that are recognised by Site as having special significance are qualified by namespaces reserved by Site. These always start with juxt and there are a handful of namespaces which are used, such as juxt.http, juxt.site and juxt.pass.

It’s important to understand that these XTDB documents are your documents, with attributes you choose from your domain. The documents are merely augmented with additional non-conflicting attributes recognised by Site.

Table 1. HTTP protocol mappings to XTDB document attributes
Web XTDB

URI

:xt/id

Methods

:juxt.site.alpha/methods

Representations

:juxt.site.alpha/variant-of

Body

:juxt.http.alpha/body, :juxt.http.alpha/content

Content Type

:juxt.http.alpha/content-type

Content Language

:juxt.http.alpha/content-language

Content Location

:juxt.http.alpha/content-location

Content Encoding

:juxt.http.alpha/content-encoding

Last-Modified

:juxt.http.alpha/last-modified

ETag

:juxt.http.alpha/etag

Content Length

:juxt.http.alpha/content-length

Trailer

:juxt.http.alpha/trailer

Transfer-Encoding

:juxt.http.alpha/transfer-encoding

Vary

:juxt.http.alpha/vary

OPTIONS

:juxt.http.alpha/options

XTDB is to Site what a file-system is to a static web-server, such as Apache.

Apache encodes web metadata in the filename. For example, the filename foo.en.html.gz encodes the language (English), media-type (HTML) and encoding (gzip) into the filename.

Site takes a different approach, using the database to encode web metadata where it can be more easily managed, queried and updated.

A database is simply a better place for web resource metadata than a file-system.

For the remainder of this section we’ll discuss a selection of these special Site attributes.

Methods

The :juxt.site.alpha/methods attribute value is a map of entries, one for each web method.

The value of each entry is another map, which contains configuration data for the web method.

Only methods included in this map are allowed by the resource. If not specified, a request method will be met with a 405 No Such Method response.

These methods are also used to generate the Allow header in web responses, where applicable.

For instance, the actions that are used for each method are listed in the juxt.pass.alpha/operations entry.

When Site receives a web request for a resource it will look for a juxt.site.alpha/methods entry which indicates which operation or actions should be used when seeking permission.

In effect, this allows the resource to indicate which rules are to be used in determining whether a user can access the resource.

A :juxt.site.alpha/methods entry shows an example of a :juxt.site.alpha/methods entry.

Example 2. A :juxt.site.alpha/methods entry
{:juxt.site.alpha/methods
  {:get
    {:juxt.pass.alpha/operations
      #{"https://site.test/operations/get-shopping-list"}}
   :post
    {:juxt.pass.alpha/operations
      #{"https://site.test/operations/post-shopping-list-item"}}}}

Publishing a public resource

Let’s publish a resource to Site that everyone can see.

Note
In many organisations, publishing information to the public web may well be a restricted operation, so the operation might be restricted to authorized users.

We’ll need to perform these steps:

  1. Create an operation for accessing a public resource

  2. Grant the permission for anyone to perform this operation

  3. Create an operation for creating a public resource

  4. Grant the permission for the REPL user to perform this operation

Let’s start with the first operation, shown in Accessing a public resource.

Example 3. Accessing a public resource
link:../../test/juxt/book.clj[role=include]
  1. We use a more appropriate scope that better reflects this operation.

  2. This is a very weak rule that matches a particular permission.

Important

Copy the code in Accessing a public resource, paste it into a REPL and evaluate.

A Permission must exist for an Operation to be allowed.

Example 4. Creating the permission for everyone to access public resources
link:../../test/juxt/book.clj[role=include]
Important

Copy the code in Creating the permission for everyone to access public resources, paste it into a REPL and evaluate.

Now we create the Operation that can be used to create public resources. The Operation ensures that the resources it creates set the correct methods (GET, HEAD and OPTIONS) and the corresponding Operations those methods map onto.

For instance, a GET request on resources created with this Operation would correspond to the https://site.test/operations/get-public-resource operation we created in Accessing a public resource.

[ex-create-public-resource] demonstrates the creation of our Operation at the REPL.

Example 5. Creating the Operation to create a public resource
link:../../test/juxt/book.clj[role=include]
  1. We’ll put this operation in the write:resource scope

  2. We add (or override) the HTTP methods allowed on this resource. Each entry is a mapping from an allowed method to a set of actions. This restricts the search for permissions to a set of actions. The fact that we don’t specify any methods such as PUT, POST or DELETE that will change the resource is the reason we’ve named this operation as creating an immutable public resource.

  3. This rule ensures this operation must be specifically granted to someone.

Important

Copy the code in [ex-create-public-resource], paste it into a REPL and evaluate.

We mustn’t forget to grant permission for our REPL user to perform this operation. This is shown in Granting permission to create a public resource.

Example 6. Granting permission to create a public resource

In this example, we allow anyone with the role of Administrator to perform the operation of creating public resources.

link:../../test/juxt/book.clj[role=include]
Important

Copy the code above, paste it into a REPL and evaluate.

Hello World!

Finally we can demonstrate that the operation we created in Creating the Operation to create a public resource.

To demonstrate our new put-immutable-public-resource operation, let’s publish a resource that will print Hello World! on a web page.

Example 7. Creating a simple public 'Hello World' resource
link:../../test/juxt/book.clj[role=include]
Important

Copy the code in Creating a simple public 'Hello World' resource above, paste it into a REPL and evaluate.

Now we can test access with curl:

curl -i https://site.test/hello

You should get a 200 response similar to this:

HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Mon, 28 Mar 2022 00:15:15 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
site-request-id: https://site.test/_site/requests/f8a1a799c72e28ec2409c1d5
permissions-policy: interest-cohort=()

Hello World!