Skip to content

Commit

Permalink
Signposting (#1055)
Browse files Browse the repository at this point in the history
* Signposting

* Consistency

* Fixing bad copy/paste on header output
  • Loading branch information
dannylamb authored and mjordan committed Mar 14, 2019
1 parent a35b88b commit 352d0dd
Showing 1 changed file with 120 additions and 0 deletions.
120 changes: 120 additions & 0 deletions docs/technical-documentation/rest-signposting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Signposting

Signposting is a technique used in RESTful APIs where other relevant resources are exposed to clients as `Link` headers in
`GET` and `HEAD` requests. These `Link` headers follow a standard format as specified in [RFC8288](
https://tools.ietf.org/html/rfc8288). Drupal already makes use of this technique for content entities, and Islandora takes it
even further by providing additional `Link` headers that enable the client to navigate the repository and discover
additional information about various resources. Because the links are returned in respionse headers, they can be relied upon
without having to parse the message body. This makes them consistent across all serialization formats that can be returned in a message body
(XML, JSON, JSONLD, etc...).

As a general precaution, link headers for Drupal entities are not exposed to users that do not have the permissions to view
the entity linked in the header. So making GET and HEAD requests anonymously will yield a different set of headers than
what an authenticated user would see. For example, anonymous users don't have the `view media` permission, so they will not
see the link headers for media associated with a node.

## Link Headers Provided by Islandora

### Alternate Representations
Other representations generated by different serializers available through Drupal's REST API are exposed as link headers
with `rel="alternate"` and `type` equal to the mimetype that will be received when dereferencing the link. For example,
if an entity in Drupal has a JSONLD representation, then the link header returned in a GET or HEAD response would look like

`Link: <http://example.org/node/1?_format=jsonld>; rel="alternate"; type="application/ld+json"`

### Referenced Entities

Entity reference fields are exposed as link headers with `rel="related"` and a title equal to the entity reference field's display label.
For example, if `http://example.org/node/1` has an entity reference field name "Associated Content" that references
`http://example.org/node/2`, then the link header returned in a GET or HEAD response would look like

`Link: <http://example.org/node/2>; rel="related"; title="Associated Content"`

### Referenced Taxonomy Terms

Entity reference fields for taxonomy terms get special handling. The taxonomy terms used to tag content are exposed as link headers
with `rel="tag"` and a title equal to the taxonomy term's display label. If the term has an external URI in a controlled vocabulary,
then that URI is provided. Otherwise, the local Drupal URI is provided. For example, if a piece of content is tagged with
`taxonomy/term/1`, which has a display label of "Example Term", then the link header returned in a GET or HEAD response would look like

`Link: <http://example.org/taxonomy/term/1>; rel="tag"; title="Example Term"`

If instead the term were to have the `field_external_uri` field with a value of `http://exampletwo.org/vocab#term` then the link
header would look like

`Link: <http://exampletwo.org/vocab#term>; rel="tag"; title="Example Term"`.

### Associated Media

Media entities belonging to nodes are exposed as link headers with `rel="related"` and a title equal to the display label of
their `field_media_use` taxonomy term. For example, if a media is tagged as `Original File` indicating
that it is the initial file uploaded, the link header returned in a GET or HEAD response for a node would look like

`Link: <http://example.org/media/1>; rel="related"; title="Original File"`.

### Source Files

Files that are the source for media entities are exposed as Link headers in the GET and HEAD responses with `rel="describes"`.
The endpoint to edit the contents of the source file is also exposed using `rel="edit-media"`. For example, if
`http://example.org/media/1` has the source file `http://example.org/file.txt`, then a GET or HEAD response would contain
both

- `Link: <http://example.org/file.txt>; rel="describes"`
- `Link: <http://example.org/media/1/source>; rel="edit-media"`

## Examples

### Requesting a Node

After creating a node, adding it to a Collection, uploading a file and kicking off derivatives, the link headers returned
for said node would look like the following. Note that non-Link headers have been removed for brevity:

```bash
vagrant@claw:~$ curl -I http://localhost:8000/node/1?_format=json
HTTP/1.1 200 OK
...
# These are provided by Drupal core
Link: <http://localhost:8000/node/1>; rel="canonical"
Link: <http://localhost:8000/node/1/delete>; rel="https://drupal.org/link-relations/delete-form"
Link: <http://localhost:8000/admin/content/node/delete?node=1>; rel="https://drupal.org/link-relations/delete-multiple-form"
Link: <http://localhost:8000/node/1/edit>; rel="edit-form"
Link: <http://localhost:8000/node/1/revisions>; rel="version-history"
Link: <http://localhost:8000/node/1>; rel="https://drupal.org/link-relations/revision"
Link: <http://localhost:8000/node?node=1>; rel="https://drupal.org/link-relations/create"

# These are provided by Islandora
Link: <http://localhost:8000/node/2>; rel="related"; title="Member of"
Link: <http://purl.org/coar/resource_type/c_c513>; rel="tag"; title="Image"
Link: <http://localhost:8000/media/1>; rel="related"; title="Original File"
Link: <http://localhost:8000/media/2>; rel="related"; title="Service File"
Link: <http://localhost:8000/media/3>; rel="related"; title="Thumbnail Image"
Link: <http://localhost:8000/node/1?_format=jsonld>; rel="alternate"; type="application/ld+json"
```

### Requesting a Media
If we were to inspect one of the Media associated with this node (which we would've gotten in the response above), the
results would look like:

```bash
vagrant@claw:~$ curl -I http://localhost:8000/media/1?_format=json
HTTP/1.1 200 OK
...

# These are provided by Drupal core
Link: <http://localhost:8000/media/add>; rel="https://drupal.org/link-relations/add-page"
Link: <http://localhost:8000/media/add/image>; rel="https://drupal.org/link-relations/add-form"
Link: <http://localhost:8000/media/1>; rel="canonical"
Link: <http://localhost:8000/admin/content/media>; rel="collection"
Link: <http://localhost:8000/media/1/delete>; rel="https://drupal.org/link-relations/delete-form"
Link: <http://localhost:8000/media/delete?media=1>; rel="https://drupal.org/link-relations/delete-multiple-form"
Link: <http://localhost:8000/media/1/edit>; rel="edit-form"
Link: <http://localhost:8000/media/1>; rel="https://drupal.org/link-relations/revision"

# These are provided by Islandora
Link: <http://localhost:8000/node/1>; rel="related"; title="Media of"
Link: <http://pcdm.org/use#OriginalFile>; rel="tag"; title="Original File"
Link: <http://localhost:8000/media/1?_format=jsonld>; rel="alternate"; type="application/ld+json"
Link: <http://localhost:8000/media/1/source>; rel="edit-media"
Link: <http://localhost:8000/_flysystem/fedora/2019-03/IF-Org-Chart_0.jpg>; rel="describes"; type="image/jpeg"

```

0 comments on commit 352d0dd

Please sign in to comment.