Hi Everyone,
I’ve been looking at using Omeka S’ API to import existing websites in to our new exhibiting tool
The API docs themselves are quite light on detail and include very few examples so I’ve spent a lot of time searching for extra information to improve my understanding of the problems I’m facing.
https://omeka.org/s/docs/developer/key_concepts/api/
To try and help a future searcher (possibly me, possibly someone else) I’m posting some API usage examples. A collection of resources I used to figure things out are included but I wasn’t keeping very good records which is one reason not everything has an existing source.
Creating an item set
This should be done before creating a site so you can configure the site to use your resulting item set from the start.
This appears to have no input validation: sets can be created with empty or duplicate titles.
curl -H 'Content-type: application/json' --data-raw '{"dcterms:title" : [ { "type" : "literal", "property_label" : "Title", "@value" : "Tasmanian History Companion (Images)", "property_id" : 1 } ]}' -s 'https://example.org/api/item_sets?key_identity=EXAMPLE_KEY&key_credential=EXAMPLE_CRED' |json_pp
Creating a site
curl -H 'Content-type: application/json' --data-raw '{"o:slug": "a-new-site-2", "o:theme": “my-default", "o:title": "My testing site has a name", "o:site_item_set" : [ { "o:item_set" : { "o:id" : "896" } } ]}' -s 'https://example.org/api/sites?key_identity=EXAMPLE_KEY&key_credential=EXAMPLE_CRED' |json_pp
Creating a page in a site
This requires a title, slug and site be provided. Its also quite fussy about slugs, only allowing [09azAZ-_].
curl -H 'Content-type: application/json' --data-raw '{ "o:slug": "A-Apple-htm", "o:site": { "@id" : "https://example.org/api/sites/12", "o:id": 12 }, "o:title": "My first API test page" }' -s 'https://example.org/api/site_pages?key_identity=EXAMPLE_KEY&key_credential=EXAMPLE_CRED' |json_pp
{
"o:block" : [
{
"o:data" : [],
"o:layout" : "pageTitle",
"o:attachment" : []
}
],
"@id" : "https://example.org/api/site_pages/119",
"o:site" : {
"o:id" : 12,
"@id" : "https://example.org/api/sites/12"
},
"o:created" : {
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime",
"@value" : "2019-01-29T05:05:02+00:00"
},
"o:slug" : "A-Apple-htm",
"@type" : "o:SitePage",
"o:id" : 119,
"o:modified" : {
"@value" : "2019-01-29T05:05:02+00:00",
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime"
},
"o:title" : "My first API test page",
"@context" : "https://example.org/api-context"
}
In some cases (like this page creation) lack of authentication returns a ‘not found’ error rather than ‘denied’ which I found rather unexpected (though was able to rationalise afterward)
curl -H 'Content-type: application/json' --data-raw '{ "o:slug": "test_01", "o:site": { "@id" : "https://example.org/api/sites/12", "o:id": 12 }, "o:title": "My first API test page" }' -s https://example.orgapi/site_pages |json_pp
{
"errors" : {
"error" : "Omeka\\Entity\\Site entity with criteria {\"id\":12} not found"
}
}
Creating an item
This creates an item without any media attached.
Will happily make entries with no titles or duplicate titles, but if a title is to be included all values in dcterms:title must be filled.
curl -H 'Content-type: application/json' --data-raw '{ "dcterms:title" : [ {"property_id": 1, "property_label" : "Title", "@value" : "My snappy title", "type" : "literal" } ], "@type" : "o:Item", "o:item_set" : [ {"o:id": 894}], "o:media" : [] }' -s 'https://example.org/api/items?key_identity=EXAMPLE_KEY&key_credential=EXAMPLE_CRED' |json_pp
{
"o:item_set" : [
{
"@id" : "https://example.org/api/item_sets/894",
"o:id" : 894
}
],
"@context" : "https://example.org/api-context",
"o:is_public" : true,
"o:resource_class" : null,
"@id" : "https://example.org/api/items/905",
"o:created" : {
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime",
"@value" : "2019-01-30T00:06:24+00:00"
},
"dcterms:title" : [
{
"property_id" : 1,
"@value" : "My snappy title",
"property_label" : "Title",
"type" : "literal"
}
],
"o:modified" : {
"@value" : "2019-01-30T00:06:24+00:00",
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime"
},
"o:resource_template" : null,
"o:media" : [],
"@type" : "o:Item",
"o-module-comment:comment" : [],
"o:owner" : {
"o:id" : 24,
"@id" : "https://example.org/api/users/24"
},
"o:id" : 905
}
Item with media included
I had to re-read the API docs several times, plus understand the various examples using curl before I understood how it was supposed to tie together - now it seems so obvious.
curl -F 'data={ "dcterms:title" : [ {"property_id": 1, "property_label" : "Title", "@value" : "My snappy title API upload style", "type" : "literal" } ], "@type" : "o:Item", "o:item_set" : [ {"o:id": 894}], "o:media" : [{"o:ingester": "upload", "file_index": "0", "o:item": {}, "dcterms:title" : [ { "property_id" : 1, "property_label" : "Title", "@value" : "My media upload title", "type" : "literal" } ]}] }' \
> -F 'file[0]=@./test-file.txt' -s 'https://example.org/api/items?key_identity=EXAMPLE_KEY&key_credential=EXAMPLE_CRED' |json_pp
{
"@id" : "https://example.org/api/items/910",
"@context" : "https://example.org/api-context",
"o:modified" : {
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime",
"@value" : "2019-01-30T00:57:29+00:00"
},
"o:media" : [],
"o:owner" : {
"@id" : "https://example.org/api/users/24",
"o:id" : 24
},
"o:item_set" : [
{
"o:id" : 894,
"@id" : "https://example.org/api/item_sets/894"
}
],
"o:resource_class" : null,
"o:created" : {
"@value" : "2019-01-30T00:57:29+00:00",
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime"
},
"dcterms:title" : [
{
"property_id" : 1,
"property_label" : "Title",
"type" : "literal",
"@value" : "My snappy title API upload style"
}
],
"o-module-comment:comment" : [],
"o:is_public" : true,
"o:resource_template" : null,
"@type" : "o:Item",
"o:id" : 910
}
Update
Multiple files can be uploaded with the same item, you are required to add extra metadata for each file in your uploads media section or the un described files will be ignored.
curl -F 'data={ "dcterms:title" : [ {"property_id": 1, "property_label" : "Title", "@value" : "My snappy title API upload style", "type" : "literal" } ], "@type" : "o:Item", "o:item_set" : [ {"o:id": 894}], "o:media" : [{"o:ingester": "upload", "file_index": "0", "o:item": {}, "dcterms:title" : [ { "property_id" : 1, "property_label" : "Title", "@value" : "My media upload title", "type" : "literal" } ]},{"o:ingester": "upload", "file_index": "1", "o:item": {}, "dcterms:title" : [ { "property_id" : 1, "property_label" : "Title", "@value" : "My media upload title for file two", "type" : "literal" } ]}] }' -F 'file[0]=@./test-file.txt' -F 'file[1]=@./test-file-2.txt' -s 'https://example.org/api/items?key_identity=EXAMPLE&key_credential=EXAMPLE' |json_pp
{
"o:is_public" : true,
"o-module-comment:comment" : [],
"o:resource_template" : null,
"@context" : "https://example.org/api-context",
"o:resource_class" : null,
"o:id" : 926,
"o:item_set" : [
{
"o:id" : 894,
"@id" : "https://example.org/api/item_sets/894"
}
],
"o:owner" : {
"o:id" : 24,
"@id" : "https://example.org/api/users/24"
},
"o:modified" : {
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime",
"@value" : "2019-01-30T01:47:20+00:00"
},
"o:created" : {
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime",
"@value" : "2019-01-30T01:47:20+00:00"
},
"dcterms:title" : [
{
"property_label" : "Title",
"property_id" : 1,
"type" : "literal",
"@value" : "My snappy title API upload style"
}
],
"@id" : "https://example.org/api/items/926",
"o:media" : [
{
"o:id" : 927,
"@id" : "https://example.orgapi/media/927"
},
{
"o:id" : 928,
"@id" : "https://example.org/api/media/928"
}
],
"@type" : "o:Item"
}
Uploading files/media individually
Item ID (of the item to be attached to) has to already be known, so if possible upload media with the item it is joined with
No sanity checking is performed, this same file can be added repeatedly without warning.
curl -s -F 'file[0]=@./test-file.txt' -F 'data={"o:ingester": "upload", "file_index": "0", "o:item": {"o:id": 888}}' 'https://example.org/api/media?key_identity=EXAMPLE_KEY&key_credential=EXAMPLE_CRED' |json_pp
{
"o-module-alt-text:alt-text" : null,
"o:modified" : {
"@value" : "2019-01-29T23:46:49+00:00",
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime"
},
"o:ingester" : "upload",
"@type" : "o:Media",
"o:lang" : null,
"o:source" : "test-file.txt",
"@context" : "https://example.org/api-context",
"o:id" : 900,
"o:resource_class" : null,
"o:thumbnail_urls" : [],
"o:sha256" : "22a4b014c1724699531d0cb649cf8c29db5e6461a37df4f4654df520779fe2d7",
"o:renderer" : "file",
"o:owner" : {
"@id" : "https://example.org/api/users/24",
"o:id" : 24
},
"@id" : "https://example.org/api/media/900",
"o:media_type" : "text/plain",
"o:created" : {
"@value" : "2019-01-29T23:46:49+00:00",
"@type" : "http://www.w3.org/2001/XMLSchema#dateTime"
},
"o:filename" : "40e82c897fd6fe517eec697085033a4967eba765.txt",
"o:is_public" : true,
"data" : [],
"o:item" : {
"@id" : "https://example.org/api/items/888",
"o:id" : 888
},
"o:original_url" : "https://example.org/files/original/40e82c897fd6fe517eec697085033a4967eba765.txt",
"o:resource_template" : null,
"o:size" : 24
}
Also note that extensions need to sit in the permitted list - configurable at https://example.org/admin/setting
References
Thats all I have at the moment but hopefully it helps someone else to understand the Omeka S API.
Karl.