Annotation
Annotations returned by the API either by themselves or embedded in a parent object, should be in the following format.
The annotation server tries to keep output format close to the format of Mirador-created annotations. In the examples below, the “Canonical” tab shows the format from the current version of Mirador. The “old” format is still supported as of Mirador v2.6.
The main difference is the “on” field. In the new format, “on” is an array, and the selector is of type “oa:Choice” and contains both rectagular boundary and the SVG shape. The old format has “on” as a single object and selector doesn’t contain the rectangular boundary.
{
"@id": "http://annotations.ten-thousand-rooms.yale.edu/annotations/e8a459bb-119c-4f46-87a3-93edc2cd22c1",
"@type": "oa:Annotation",
"@context": "http://iiif.io/api/presentation/2/context.json",
"resource": [
{
"@type": "dctypes:Text",
"format": "text/html",
"chars": "<p>Test #1</p>"
},
{
"@type": "oa:Tag",
"chars": "mytag"
}
],
"within": [
"http://annotations.ten-thousand-rooms.yale.edu/lists/http://manifest.tenthousandrooms.yale.edu/layers/16_http://manifest.tenthousandrooms.yale.edu/node/311/canvas/14116"
],
"motivation": [
"oa:commenting"
],
"on": [
{
"@type": "oa:SpecificResource",
"full": "http://manifest.tenthousandrooms.yale.edu/node/311/canvas/14116",
"selector": {
"@type": "oa:Choice",
"default": {
"@type": "oa:FragmentSelector",
"value": "xywh=54,248,179,219"
},
"item": {
"@type": "oa:SvgSelector",
"value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M53.93942,248.15395h89.65346v0h89.65346v109.58331v109.58331h-89.65346h-89.65346v-109.58331z\" data-paper-data=\"{"strokeWidth":1,"rotation":0,"deleteIcon":null,"rotationIcon":null,"group":null,"editable":true,"annotation":null}\" id=\"rectangle_f95e7e02-7a2b-495e-8dc4-d47f1c0fba9d\" fill-opacity=\"0\" fill=\"#00bfff\" fill-rule=\"nonzero\" stroke=\"#00bfff\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" style=\"mix-blend-mode: normal\"/></svg>"
}
},
"within": {
"@id": "http://manifest.tenthousandrooms.yale.edu/node/311/manifest",
"@type": "sc:Manifest"
}
}
],
"layerId": "http://manifest.tenthousandrooms.yale.edu/layers/16"
}
{
"@id": "http://annotations.ten-thousand-rooms.yale.edu/annotations/215bc9b4-ca41-4467-a823-4440c420eb8e",
"@type": "oa:annotation",
"@context": "http://iiif.io/api/presentation/2/context.json",
"resource": [
{
"@type": "dctypes:Text",
"format": "text/html",
"chars": "<p>《孔子集語》 </p>"
}
],
"within": [
"http://annotations.ten-thousand-rooms.yale.edu/lists/http://manifest.tenthousandrooms.yale.edu/layers/16_http://manifest.tenthousandrooms.yale.edu/node/311/canvas/14116",
"http://annotations.tenkr.yale.edu/annotations/lists/http://ten-thousand-rooms.herokuapp.com/layers/5557c1c3-53d5-4af5-bfc8-990008826fcc_http://manifest.tenthousandrooms.yale.edu/node/311/canvas/14116"
],
"motivation": [
"oa:commenting"
],
"on": {
"@type": "oa:SpecificResource",
"full": "http://manifest.tenthousandrooms.yale.edu/node/311/canvas/14116",
"selector": {
"@type": "oa:SvgSelector",
"value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M292.21935,122.21566l109.99409,0l109.99409,0l0,476.64106l0,476.64106l-109.99409,0l-109.99409,0l0,-476.64106z\" data-paper-data=\"{"rotation":0,"annotation":null}\" id=\"rectangle_647a69af-6014-412d-8c28-6e561ec82dde\" fill-opacity=\"0\" fill=\"#00bfff\" stroke=\"#00bfff\" stroke-width=\"1.74594\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"sans-serif\" font-weight=\"normal\" font-size=\"12\" text-anchor=\"start\" mix-blend-mode=\"normal\"/></svg>"
}
},
"layerId": "http://manifest.tenthousandrooms.yale.edu/layers/16"
}
Authentication
Authentication for create, update, and delete operations are handled through JWT tokens. Mirador is initialized with a token for the project and the user from the Drupal portal and passes it to annotation server along with its ajax requests. The annotation server decodes the token using a shared key and queries the portal to see if the user is allowed to perform the operation.
Dependencies
API dependencies
${drupal_portal_url}/has-canvas-access?canvas_id=${canvas_id}&user_id=${user_id}
- to check if the user ID (extracted from the JWT token) has permission for the canvas. In Drupal, this API is impemented as a view with a contextual filter.${drupal_portal_url}/node/#{project_id}/collection?user_id=#{user_id}
- to get collection information for exporting annotations data for the project.
Imagemagick
- The
feed_for_search:bounding_boxes
rake task depends on thermagick
gem, which in turn depends on the native installation of Imagemagick (note: version 6, not 7).
Environment
Environment Variables
IIIF_HOST_URL | Entity IDs will be prefixed with this URL |
USE_REDIS | If Y , /getAnnotationsList is served from the Redis cache |
S3_Bucket | URL of the S3 bucket to which export and search feed files are uploaded |
S3_Bucket_Folder | Folder name under the said S3 bucket |
S3_Key | S3 credential |
S3_Secret | S3 credential |
S3_PUBLIC_DOWNLOAD_PREFIX | URL prefix from which to download exported CSV files |
IIIF_COLLECTIONS_HOST | URL of host that provides the collection information for exports |
USE_JWT_AUTH | If ‘Y’, authenticate the REST API using JWT tokens |
For local development only:
DB_HOST_DEV
DATABASE_DEV
DB_USERNAME_DEV
DB_PASSWORD_DEV
DB_HOST_TEST
DATABASE_TEST
DB_USERNAME_TEST
DB_PASSWORD_TEST
Life of the Buddha
The features unique to the Life of the Buddha project have been omitted from this documentation.
API
/setRedisKeys
- reload redis cache
Offline tasks
Various tasks that import annotations data from Google Docs.
/getAnnotationsViaList
Get annotations on the canvas
Parameters
- canvas_id
- ID of canvas
e.g.http://example.org/iiif/canvas/1
(required)
Returns all annotations (along with the IDs of the layers to which they belong) that are associated with the canvas transitively, i.e., recursively including annotations that target those annotations, thus indirectly targeting the canvas.
[
{
"layer_id" : "<Layer ID>",
"annotation": "<See Documentation/Annotation section>"
},
...
]
jQuery.ajax({
url: "https://mirador-annotations-lotb-stg.herokuapp.com/getAnnotationsViaList?canvas_id=http%3A%2F%2Fmanifests.ydc2.yale.edu%2FLOTB%2Fcanvas%2Fpanel_01",
type: 'GET',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: (data, textStatus, jqXHR) => {
console.log('Success', data);
},
error: (jqXHR, textStatus, errorThrown) => {
console.log('Error', jqXHR);
}
});
/annotations/<id>
Get a specific annotation
Example: http://example.org/annotations/215bc9b4-ca41-4467-a823-4440c420eb8e
/annotations
Create an annotation
Payload:
{
"layer_id": "<Layer ID>",
"annotation": "<See Documentation/Annotation section>"
}
annotation["@id"]
is not required because it will be created by the server and included in response.
/annotations
Update annotation
Payload:
{
"layer_id": [ "<Layer ID>" ],
"annotation": "<See Documentation/Annotation section>"
}
/annotations
Delete annotation
The whole URL of the request is identical to the IIIF style annotation ID, e.g.,
http://annotations.ten-thousand-rooms.yale.edu/annotations/76d24e36-e255-41db-883f-64606c4ff08e
/layers
Get annotation layers
Parameters
- group_id
- Group ID of current user.
When specified, returns list of layers that are defined for the group (or project).
(optional - currently used for Ten Thousand Rooms only.)
[
{
"@context": "http://iiif.io/api/presentation/2/context.json",
"@id": "http://manifest.tenthousandrooms.yale.edu/layers/16",
"@type": "sc:Layer",
"label": "Transcription"
},
...
]
/resequenceList
Re-order annotations in a list
Payload:
{
"canvas_id": "<Canvas ID>",
"layer_id": "<Layer ID>",
"annotation_ids": [ "<AnnotationID>", ... ]
}
canvas_id
and layer_id
together determines the list the user wants to change.
annotation_ids
is a list of annotation IDs that are arranged in the new updated order.
/export
Export annotations
Parameters
- user_id
- User ID from drupal
(required) - project_id
- Project ID from drupal
(required)
/export/check_status
Called by client-side JavaScript in intervals to update the status of the export job -- whether it is in progress or complete.
Parameters
- job_id
- ID of the Delayed::Job job
Used by the export page to check the progress of the offline export task. It should initiate download when the status indicates the job is complete.
/setCurrentLayers
Set layers (called from drupal)
Payload:
{
"group_id": "<Group ID>",
"group_description": "<Node title>",
"layers": [
{
"layer_id": "<Layer ID>",
"label": "<label>"
},
...
]
}
Feed for search
Exports annotations data into csv files and uploads them to S3 so the drupal portal will consume them to feed the Solr search engine.
Rake tasks
feed_for_search:bounding_boxes
feed_for_search:annos_no_resource
feed_for_search:annos_resource_only