How-tos

This document assumes a basic familiarity with:

  • HTTP protocol and web concepts
  • Object storage concepts
  • Command-line environments and the curl utility

See the REST API documentation for a complete overview of the supported resources and operations with detailed HTTP protocol information.

Background

Hatrac provides a client-controlled namespace hierarchy with client-named objects containing arbitrary data content. In short, a Hatrac namespace is similar to a directory in a traditional filesystem, while a Hatrac object is similar to a file.

However, a single Hatrac object name may have multiple content versions. Each version is given a unique, psuedo-random version identifier when it is created. Any particular object version is immutable and can only ever be seen with the same content that was provided atomically when it was created. The bare object name implicitly references the latest available version, while version-qualified names reference the particular version no matter what other updates are performed on the object.

Examples

In the following examples, let’s assume that Hatrac is deployed with a webauthn2 configuration that uses local database providers. Furthermore, assume that a test user test-user-1 is defined and has been assigned an attribute my-admin-group. For this deployment, assume the hostname server.example.org is hosting the service stack.

Deploying

This command initializes the deployment so that users with the my-admin-group attribute are granted full privileges on the root namespace:

hatrac-deploy "my-admin-group"

Authentication using Database Providers

Hatrac currently depends on a sibling ERMrest deployment to have access to its embedded webauthn2 security service for login. With the webauthn2 database providers, we can login via the command-line by sending an HTTP POST request with login form fields populated:

curl -b ~/cookie -c ~/cookie \
  -d username=test-user-1 \
  -d password="my secret" \
  https://server.example.org/ermrest/authn/session

This command prints out the new session information as a JSON response (with modified whitespace here for readability):

{
  "attributes": [
    {"display_name": "my-admin-group", "id": "my-admin-group"}, 
    {"display_name": "test-user-1", "id": "test-user-1"}
  ], 
  "seconds_remaining": 1799, 
  "since": "2016-05-06 23:38:15.798275+00:00", 
  "expires": "2016-05-07 00:08:15.798275+00:00", 
  "client": {"display_name": "test-user-1", "id": "test-user-1"}
}

With other security providers, more effort is required to obtain the equivalent ~/cookie file needed for the rest of the examples below.

Listing the Root Namespace

The root namespace is listed with an HTTP GET on the namespace URL:

curl -b ~/cookie -c ~/cookie \
  https://server.example.org/hatrac/

The response represents the currently empty root namespace:

[]

Creating a Nested Namespace

The HTTP PUT operation with a special Content-Type header allows us to create a new namespace with our own chosen name:

curl -b ~/cookie -c ~/cookie \
  -H "Content-Type: application/x-hatrac-namespace" \
  -X PUT
  https://server.example.org/hatrac/folder1

The response repeats the name we have chosen for the new namespace:

/hatrac/folder1

If you repeat the namespace listing step for the root namespace, this time the response will enumerate the single child namespace:

["/hatrac/folder1"]

Creating an Object

First, let’s create a test data file:

cat > hello.txt <<EOF
> Line 1: Hello, World!
> Line 2: That's all, Folks!
EOF

Now, let’s upload it using the built-in support for file upload via HTTP PUT using curl’s -T transfer mode:

curl -b ~/cookie -c ~/cookie \
  -H "Content-Type: text/plain" \
  -T hello.txt \
  https://server.example.org/hatrac/folder1/object1

The response repeats the object name we have chosen but qualifies it with a server-generated version ID:

/hatrac/folder1/object1:SP274AQOOO3TOXIS2BVSDA5HCE

Retrieving an Object

A simple HTTP GET will retrieve an existing object’s current version:

curl -b ~/cookie -c ~/cookie \
  https://server.example.org/hatrac/folder1/object1

The response contains the object content itself:

Line 1: Hello, World!
Line 2: That's all, Folks!

Retrieving Object Metadata Too

We can also ask curl to dump the protocol headers with the response on standard output using the -D flag:

curl -b ~/cookie -c ~/cookie \
  -D - \
  https://server.example.org/hatrac/folder1/object1

The response contains the object content itself:

HTTP/1.1 200 OK
Date: Fri, 06 May 2016 23:55:28 GMT
Content-Length: 49
Content-Disposition: filename*=UTF-8''object1
ETag: "SP274AQOOO3TOXIS2BVSDA5HCE"
Vary: cookie
Content-Type: text/plain; charset=UTF-8

Line 1: Hello, World!
Line 2: That's all, Folks!

The ETag header is used to inform the HTTP client about cache validity. It happens to repeat the actual version ID but you SHOULD NOT rely on this in any client application. The Hatrac service MAY use other means for cache management in future revisions.

Updating an Object

First, let’s modify our existing data file:

cat >> hello.txt <<EOF
> Line 3: Well, I spoke too soon...
> EOF

Now, let’s upload it the same as before. The server will automatically create a new version and update the current version to point to this new one:

curl -b ~/cookie -c ~/cookie \
  -H "Content-Type: text/plain" \
  -T hello.txt \
  https://server.example.org/hatrac/folder1/object1

The response repeats the object name we have chosen but qualifies it with a server-generated version ID:

/hatrac/folder1/object1:3VJO6XIPAGVBAGPUIOMG546SWU

If you repeat the step to retrieve object and metadata, you will see the new content:

HTTP/1.1 200 OK
Date: Sat, 07 May 2016 00:00:05 GMT
Content-Length: 83
Content-Disposition: filename*=UTF-8''object1
ETag: "3VJO6XIPAGVBAGPUIOMG546SWU"
Vary: cookie
Content-Type: text/plain; charset=UTF-8

Line 1: Hello, World!
Line 2: That's all, Folks!
Line 3: Well, I spoke too soon...

Retrieving an Object Version

Simply by using the full version-qualified URL for the object, you can retrieve the older version of the object:

curl -b ~/cookie -c ~/cookie \
  -D - \
  https://server.example.org/hatrac/folder1/object1:SP274AQOOO3TOXIS2BVSDA5HCE

The response will familiar:

HTTP/1.1 200 OK
Date: Sat, 07 May 2016 00:04:55 GMT
Content-Length: 49
Content-Disposition: filename*=UTF-8''object1
ETag: "SP274AQOOO3TOXIS2BVSDA5HCE"
Vary: cookie
Content-Type: text/plain; charset=UTF-8

Line 1: Hello, World!
Line 2: That's all, Folks!

Deleting an Object Version

You can delete a specific object version and it will no longer be available for retrieval. If you delete the current version, the object will automatically revert to the latest remaining version as its new current version:

curl -b ~/cookie -c ~/cookie \
  -X DELETE \
  https://server.example.org/hatrac/folder1/object1:3VJO6XIPAGVBAGPUIOMG546SWU

This operation has no response content. If you now retrieve the unqualified object name, you’ll get the previous version again.

Deleting an Object

You can delete the entire object and all of its versions at once:

curl -b ~/cookie -c ~/cookie \
  -X DELETE \
  https://server.example.org/hatrac/folder1/object1

This operation has no response content. If you now retrieve the unqualified object name, you’ll get a 404 Not Found HTTP error.