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.
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.
{: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"}
-
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.
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 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. |
Web | XTDB |
---|---|
URI |
|
Methods |
|
Representations |
|
Body |
|
Content Type |
|
Content Language |
|
Content Location |
|
Content Encoding |
|
Last-Modified |
|
ETag |
|
Content Length |
|
Trailer |
|
Transfer-Encoding |
|
Vary |
|
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.
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.
: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"}}}}
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:
-
Create an operation for accessing a public resource
-
Grant the permission for anyone to perform this operation
-
Create an operation for creating a public resource
-
Grant the permission for the REPL user to perform this operation
Let’s start with the first operation, shown in Accessing a public resource.
link:../../test/juxt/book.clj[role=include]
-
We use a more appropriate scope that better reflects this operation.
-
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.
Note in Accessing a public resource the Rules referenced the existence of a Permission, https://site.test/permissions/public-resources-to-all
. This is created in 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.
link:../../test/juxt/book.clj[role=include]
-
We’ll put this operation in the
write:resource
scope -
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.
-
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.
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. |
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.
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!