Tools to interact with the Omeka S REST API

class OmekaAPIClient[source]

OmekaAPIClient(api_url, key_identity=None, key_credential=None, use_cache=True)

First import the OmekaAPIClient class.

from omeka_s_tools.api import OmekaAPIClient

To initialise the OmekaAPIClient you need to provide the base url of your Omeka instance's API.

omeka = OmekaAPIClient('http://timsherratt.org/collections/api')

This will let you access details of all public resources provided by your Omeka instance. To access private resources, or create new resources, you'll have to authenticate your API requests by provide a key_identity and key_credential. See Adding items for an example.

Getting resources

You can find a full list of Omeka's resources in the API documentation. You're most likely to be interested in 'items', but accessing 'properties' and 'resource_templates' can be useful when you're creating new resources.

You should be able to use get_resources with any of the resource types, though some of the parameters will be different.

OmekaAPIClient.get_resources[source]

OmekaAPIClient.get_resources(resource_type, **kwargs)

Get a list of resources matching the supplied parameters. This will return the first page of matching results. To retrieve additional pages, you can supply the page parameter to move through the full result set.

Parameters:

  • resource_type - one of Omeka's resource types, eg: 'items', 'properties'
  • there are many additional parameters you can supply as kwargs, see the Omeka documention

Returns a dict with the following values:

  • total_results - number of matching resources
  • results - a list of dicts, each containing a JSON-LD formatted representation of a resource
data = omeka.get_resources('items')
data['total_results']
120
assert isinstance(data['total_results'], int)
data = omeka.get_resources('resource_templates')
first_template = data['results'][0]
assert first_template['@type'] == 'o:ResourceTemplate'

OmekaAPIClient.get_resource_by_id[source]

OmekaAPIClient.get_resource_by_id(resource_id, resource_type='items')

Get a resource from its Omeka id.

Parameters:

  • resource_id - numeric identifier used by Omeka for this resource
  • resource_type - one of Omeka's resource types, eg: 'items', 'properties'

Returns

  • a dict containing a JSON-LD formatted representation of the resource
data = omeka.get_resources('items')
random_item = random.choice(data['results'])
item_id = random_item['o:id']

# Get the same item using its id
item_from_id = omeka.get_resource_by_id(item_id, 'items')

# Check that they're the same
assert random_item == item_from_id

It can be difficult to remember all the available parameters and the differences between resource types, so I've created a number of more specialised methods that are really just wrappers around get_resources.

OmekaAPIClient.get_template_by_label[source]

OmekaAPIClient.get_template_by_label(label)

Get a resource template from its Omeka label.

Parameters:

  • label - the name of the resource template in Omeka (eg. 'NewspaperArticle')

Returns:

  • dict containing representation of the template
newspaper_template = omeka.get_template_by_label('Newspaper')

assert newspaper_template['@type'] == 'o:ResourceTemplate'
assert newspaper_template['o:label'] == 'Newspaper'
template_from_list = random.choice(omeka.get_resources('resource_templates')['results'])
label = template_from_list['o:label']

# Get the template using label
template_from_label = omeka.get_template_by_label(label)

# Check they're both the same
assert template_from_list == template_from_label

OmekaAPIClient.get_resource_by_term[source]

OmekaAPIClient.get_resource_by_term(term, resource_type='properties')

Get the resource (property or class) associated with the suppied term.

Parameters:

  • term - property label qualified with vocabulary prefix (eg: 'schema:name')

Returns:

  • dict containing representation of the resource
prop = omeka.get_resource_by_term('schema:name')
prop
{'@context': 'http://timsherratt.org/collections/api-context',
 '@id': 'http://timsherratt.org/collections/api/properties/1116',
 '@type': 'o:Property',
 'o:id': 1116,
 'o:local_name': 'name',
 'o:label': 'name',
 'o:comment': 'The name of the item.',
 'o:term': 'schema:name',
 'o:vocabulary': {'@id': 'http://timsherratt.org/collections/api/vocabularies/5',
  'o:id': 5}}
assert prop['@type'] == 'o:Property'
assert prop['o:term'] == 'schema:name'

OmekaAPIClient.get_resource_from_vocab[source]

OmekaAPIClient.get_resource_from_vocab(local_name, vocabulary_namespace_uri='http://schema.org/', resource_type='properties')

Get the resource (property or class) associated with the suppied vocabulary and label.

Parameters:

  • local_name - label of the property or class
  • vocabulary_namespace_uri - URI defining the vocab

Returns:

  • dict containing representation of the resource
prop = omeka.get_resource_from_vocab(
    'name', 
    vocabulary_namespace_uri='http://schema.org/',
    resource_type='properties')
prop
{'@context': 'http://timsherratt.org/collections/api-context',
 '@id': 'http://timsherratt.org/collections/api/properties/1116',
 '@type': 'o:Property',
 'o:id': 1116,
 'o:local_name': 'name',
 'o:label': 'name',
 'o:comment': 'The name of the item.',
 'o:term': 'schema:name',
 'o:vocabulary': {'@id': 'http://timsherratt.org/collections/api/vocabularies/5',
  'o:id': 5}}
vocab = requests.get(prop['o:vocabulary']['@id'])
namespace_uri = vocab.json()['o:namespace_uri']

assert namespace_uri == 'http://schema.org/'
assert prop['o:local_name'] == 'name'

OmekaAPIClient.get_property_id[source]

OmekaAPIClient.get_property_id(term)

Get the numeric identifier associated with the supplied property term.

Parameters:

  • term - property label qualified with vocabulary prefix (eg: 'schema:name')

Returns:

  • numeric identifier
prop_id = omeka.get_property_id('schema:name')
prop_id
1116
assert isinstance(prop_id, int)

prop = omeka.get_resource_by_id(prop_id, 'properties')
assert prop['o:term'] == 'schema:name'

OmekaAPIClient.filter_items_by_property[source]

OmekaAPIClient.filter_items_by_property(filter_property='schema:name', filter_value='', filter_type='eq', page=1, **extra_filters)

Filter the list of items by searching for a value in a particular property. Additional filters can also limit to items associated with particular templates, classes, or item sets.

Parameters:

  • filter_property - property term (eg: 'schema:name')
  • filter_value - the value you want to find
  • filter_type - how filter_value should be compared to the stored values (eg: 'eq')
  • page - number of results page

Additional parameters:

  • resource_template_id - numeric identifier
  • resource_class_id - numeric identifier
  • item_set_id - numeric identifier
  • is_public - boolean, True or False

Returns a dict with the following values:

  • total_results - number of matching resources
  • results - a list of dicts, each containing a JSON-LD formatted representation of a resource
items = omeka.filter_items_by_property(filter_property='schema:name', filter_value='wragge', filter_type='in')

assert len(items['results']) > 0
assert 'wragge' in items['results'][0]['schema:name'][0]['@value'].lower()
items['results'][0]['schema:name'][0]['@value']
'Clement Wragge at Home. - UPDATED! - UPDATED!'

OmekaAPIClient.search_items[source]

OmekaAPIClient.search_items(query, search_type='fulltext_search', page=1, **extra_filters)

Search for matching items. Two search types are available:

  • 'search` - looks for an exact match of the query in a property value
  • 'fulltext_search` - looks for the occurance of the query anywhere

Parameters:

  • query - the text you want to search for
  • search_type - one of 'fulltext_search' or 'search'
  • page - number of results page

Additional parameters:

  • resource_template_id - numeric identifier
  • resource_class_id - numeric identifier
  • item_set_id - numeric identifier
  • is_public - boolean, True or False

Returns a dict with the following values:

  • total_results - number of matching resources
  • results - a list of dicts, each containing a JSON-LD formatted representation of a resource
items = omeka.search_items('wragge')
items['total_results']
23
assert items['total_results'] >= len(items['results'])

Adding items

To add resources to Omeka you need authenticate your API requests by supplying key_identity and key_credential tokens as parameters.

omeka_auth = OmekaAPIClient(
    api_url='https://timsherratt.org/collections/api',
    key_identity=os.getenv('KEY_IDENTITY'), 
    key_credential=os.getenv('KEY_CREDENTIAL')
)

There are two stages in creating a new item:

  • prepare a payload containing the item data in the format expected by Omeka
  • upload the payload to Omeka

Prepare an item payload

OmekaAPIClient.prepare_item_payload[source]

OmekaAPIClient.prepare_item_payload(terms)

Prepare an item payload, ready for upload.

Parameters:

  • terms: a dict of terms, values, and (optionally) data types

Returns:

  • the payload dict
test_item = {
    'dcterms:title': [
        {
            'value': 'My first resource!'
        }
    ]
}
payload = omeka_auth.prepare_item_payload(test_item)
payload
{'dcterms:title': [{'property_id': 1,
   'type': 'literal',
   '@value': 'My first resource!'}]}

Each term in the payload should have values for property_id and type, and the property value should be included as either @id or @value depending on the data type.

first_property = list(payload.values())[0][0]

assert 'property_id' in first_property
assert 'type' in first_property
assert '@value' in first_property or '@id' in first_property

One of the powerful features of Omeka S is the ability to create resource templates that define a set of properties for a particular type of item. We can use templates to help create our payload, ensuring that the terms and data types we supply match those expected by the template. This is useful for identifying potential problems before we upload to Omeka, especially as Omeka will sometimes just fail silently.

OmekaAPIClient.prepare_item_payload_using_template[source]

OmekaAPIClient.prepare_item_payload_using_template(terms, template_id)

Prepare an item payload, checking the supplied terms and values against the specified template. Note:

  • terms that are not in the template will generate a warning and be dropped from the payload
  • data types that don't match the template definitions will generate a warning and the term will be dropped from the payload
  • if no data type is supplied, a type that conforms with the template definition will be used

Parameters:

  • terms: a dict of terms, values, and (optionally) data types
  • template_id: Omeka's internal numeric identifier for the template

Returns:

  • the payload dict

Once you've created a payload, you can add paths to any media files that you want to be attached to the item.

test_newspaper_item = {
    'schema:name': [
        {
            'value': 'Wragge!'
        }
    ]
}
test_newspaper_payload = omeka_auth.prepare_item_payload_using_template(test_newspaper_item, 5)
test_newspaper_payload
{'schema:name': [{'property_id': 1116,
   'type': 'literal',
   '@value': 'Wragge!'}]}
assert test_newspaper_item['schema:name'][0]['value'] == test_newspaper_payload['schema:name'][0]['@value']
assert test_newspaper_payload['schema:name'][0]['type'] == 'literal'

OmekaAPIClient.add_media_to_payload[source]

OmekaAPIClient.add_media_to_payload(payload, media_files)

Add media files to the item payload.

Parameters:

  • payload - the payload dict to be modified
  • media_files - media files to be uploaded

The value of media_files can be either:

  • a list of paths to the image/media files (filename is used as title)
  • a list of dicts, each containing title, and path values

The path values can either be strings or pathlib Paths.

Returns:

  • the modified payload dict
payload_with_media = omeka_auth.add_media_to_payload({}, media_files=['media/nla.news-article226799674-24144902.jpg'])
assert json.loads(payload_with_media['data'][1])

Upload the payload to Omeka and create a new item

OmekaAPIClient.add_item[source]

OmekaAPIClient.add_item(payload, media_files=None, template_id=None, class_id=None, item_set_id=None)

Create a new item from the supplied payload, optionally uploading attached media files.

Parameters:

  • payload - a dict generated by prepare_item_payload() or prepare_item_payload_using_template()
  • media_files - a list of paths pointing to media files, or a list of dicts with path and title values
  • template_id - internal Omeka identifier of a resource template you want to attach to this item
  • class_id - internal Omeka identifier of a resource class you want to attach to this item
  • item_set_id - internal Omeka identifier for an item set you want to add this item to

Returns:

  • a dict providing the JSON-LD representation of the new item from Omeka

Add a simple item

new_item = omeka_auth.add_item(payload)
new_item
{'@context': 'https://timsherratt.org/collections/api-context',
 '@id': 'https://timsherratt.org/collections/api/items/1038',
 '@type': 'o:Item',
 'o:id': 1038,
 'o:is_public': True,
 'o:owner': {'@id': 'https://timsherratt.org/collections/api/users/1',
  'o:id': 1},
 'o:resource_class': None,
 'o:resource_template': None,
 'o:thumbnail': None,
 'o:title': 'My first resource!',
 'thumbnail_display_urls': {'large': None, 'medium': None, 'square': None},
 'o:created': {'@value': '2022-04-04T00:47:02+00:00',
  '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},
 'o:modified': {'@value': '2022-04-04T00:47:02+00:00',
  '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},
 'o:media': [],
 'o:item_set': [],
 'o:site': [],
 'dcterms:title': [{'type': 'literal',
   'property_id': 1,
   'property_label': 'Title',
   'is_public': True,
   '@value': 'My first resource!'}]}
assert new_item['@type'] == 'o:Item'
assert test_item['dcterms:title'][0]['value'] == new_item['dcterms:title'][0]['@value']

You can also add an item to an existing item set by supplying the item_set_id parameter.

random_item_set = random.choice(omeka_auth.get_resources('item_sets')['results'])
item_set_id = random_item_set['o:id']

# Create a new item using the item set id
new_item_in_item_set = new_item = omeka_auth.add_item(payload, item_set_id=item_set_id)

# Check that the ids match
assert new_item_in_item_set['o:item_set'][0]['o:id'] == item_set_id

Updating resources

OmekaAPIClient.delete_resource[source]

OmekaAPIClient.delete_resource(resource_id, resource_type)

Deletes a resource. No confirmation is requested, so use carefully.

Parameters:

  • resource_id - local Omeka identifier of the resource you want to delete
  • resource_type - type of the resource (eg 'items')

Returns:

  • dict with JSON-LD representation of the deleted resource
data = omeka.get_resources('items')
random_item = random.choice(data['results'])

deleted_resource = omeka_auth.delete_resource(random_item['o:id'], 'items')

# The id of the deleted item should be None
assert deleted_resource['o:id'] is None

# The titles of the random and deleted items should be the same
assert deleted_resource['o:title'] == random_item['o:title']

# Trying to get the random item should now raise an HTTP 404 error
with pytest.raises(requests.exceptions.HTTPError):
    omeka_auth.get_resource_by_id(random_item['o:id'], 'items')

OmekaAPIClient.update_resource[source]

OmekaAPIClient.update_resource(payload, resource_type='items')

Update an existing resource.

Parameters:

  • payload - the updated resource data
  • resource_type - the type of resource

To avoid problems, it's generally easiest to retrieve the resource first, make your desired changes to it, then submit the updated resource as your payload.

data = omeka_auth.filter_items_by_property(filter_property='schema:name', filter_type='ex')
random_item = random.choice(data['results'])
# Original title
title = random_item['schema:name'][0]['@value']

# Copy and update the original item
new_item = deepcopy(random_item)
new_item['schema:name'][0]['@value'] = title + ' - UPDATED!'

# Update the item 
updated_item = omeka_auth.update_resource(new_item, 'items')

# Display the updated title
updated_title = updated_item['schema:name'][0]['@value']
print(updated_title)

# The id of the original and upated items should be the same
assert random_item['o:id'] == updated_item['o:id']

# But the titles should be different
assert title != updated_item['schema:name'][0]['@value']
Wellington Times (NSW : 1899 - 1954) - UPDATED! - UPDATED! - UPDATED!

OmekaAPIClient.add_media_to_item[source]

OmekaAPIClient.add_media_to_item(item_id, media_file, payload={}, template_id=None, class_id=None)

Upload a media file and associate it with an existing item.

Parameters:

  • item_id - the Omeka id of the item this media file should be added to
  • media_path - a path to an image/media file (string or pathlib Path)
  • payload (optional) - metadata to attach to media object, either a dict generated by prepare_item_payload() or prepare_item_payload_using_template(), or a string which is used as the value for dcterms:title.
  • template_id - internal Omeka identifier of a resource template you want to attach to this item
  • class_id - internal Omeka identifier of a resource class you want to attach to this item

Returns:

  • a dict providing a JSON-LD representation of the new media object
omeka_auth = OmekaAPIClient(
    api_url='https://timsherratt.org/collections/api',
    key_identity=os.getenv('KEY_IDENTITY'), 
    key_credential=os.getenv('KEY_CREDENTIAL')
)

Add a media file to an item without any additional metadata.

data = omeka_auth.get_resources('items')
item = random.choice(data['results'])
item_id = item['o:id']

# Add a new media file to the item
media_resource = omeka_auth.add_media_to_item(item_id, 'media/nla.news-article226799674-24144902.jpg')

# Check that the media resource is the expected type
assert media_resource['@type'] == 'o:Media'

# Check that the media resource is linked to the item
assert media_resource['o:item']['o:id'] == item_id

Include a title for a new media item by supplying a string value to the payload parameter.

media_resource = omeka_auth.add_media_to_item(item_id, 'media/nla.news-article226799674-24144902.jpg', payload='This has a title')

# The title should be saved as dcterms:title
assert media_resource['dcterms:title'][0]['@value'] == 'This has a title'

Include more detailed metadata with a new media item by generating a payload and supplying it using the payload parameter.

media_metadata = {
    'schema:name': ['This is a different title'],
    'schema:identifier': ['myidis3']
}

# Convert metadata into an Omeka payload
media_payload = omeka_auth.prepare_item_payload(media_metadata)

# Add a new media file with a metadata payload to the item
media_resource = omeka_auth.add_media_to_item(item_id, 'media/nla.news-article226799674-24144902.jpg', payload=media_payload)

assert media_resource['schema:name'][0]['@value'] == 'This is a different title'

Use a specific resource template with the new media item by using the template_id parameter.

data = omeka_auth.get_resources('resource_templates')
template = random.choice(data['results'])
template_id = template['o:id']

# Add a new media file and assign it to a template using the `template_id` parameter
media_resource = omeka_auth.add_media_to_item(item_id, 'media/nla.news-article226799674-24144902.jpg', payload=media_payload, template_id=template_id)

# Check the new media object has the correct template id
assert media_resource['o:resource_template']['o:id'] == template_id

OmekaAPIClient.add_marker_to_item[source]

OmekaAPIClient.add_marker_to_item(item_id, coords=None, terms=None, label=None, media_id=None)

Add a map marker to an item. Requires the mapping module to be installed.

Parameters:

  • item_id - identifier of item to add marker to
  • coords - list with coordinates in longitude, latitude order eg [151.209900, -33.865143]
  • terms - list with vocab terms containing longitude and latitude values eg ['schema:longitude', 'schema:latitude']
  • label - label for marker (defaults to item title)
  • media_id - identifier of media resource to display with marker

Returns:

  • dict providing JSON-LD representation of marker

The Omeka Mapping module lets you associate an item with a location on a map. Once you have the module installed, you can use the Omeka API to add map markers to items.

data = omeka_auth.get_resources('items')
item = random.choice(data['results'])
item_id = item['o:id']

# Add a marker using coords
marker = omeka_auth.add_marker_to_item(item_id, coords=[151.209900, -33.865143])

assert marker['@type'] == 'o-module-mapping:Marker'
assert marker['o:item']['o:id'] == item_id

You can also read the map coordinates from the item itself. By default OmekaAPIClient.add_marker_to_item will look for values in schema:longitude and schema:latitude, but you can specify the vocabulary terms that you want to look for.

Here we'll create a simple item with values for schema:longitude and schema:latitude.

test_place = {
    'schema:name': [
        {
            'value': 'Australia'
        }
    ],
    'schema:longitude': [
        {
            'value': '151.209900'
        }
    ],
    'schema:latitude': [
        {
            'value': '-33.865143'
        }
    ],
    
}

payload = omeka_auth.prepare_item_payload(test_place)
new_place = omeka_auth.add_item(payload)

Now we can just call OmekaAPIClient.add_marker_to_item without any coordinates, and it will get them from schema:longitude and schema:latitude.

new_marker = omeka_auth.add_marker_to_item(new_place['o:id'])

assert new_marker['@type'] == 'o-module-mapping:Marker'
assert new_marker['o:item']['o:id'] == new_place['o:id']
assert new_marker['o-module-mapping:lat'] == -33.865143

Managing templates

Resource templates can be exported from one Omeka instance and imported into another. This is a really useful way of sharing and resuing data structures. However, exported templates can't be uploaded via the API without some modification, as they don't include Omeka numeric identifiers for referenced classes and properties. Before uploading them, we need to find the referenced classes and properties in the local Omeka instance, and insert the local identifiers into the payload.

Similarly, if custom vocabs are referenced in the exported template, they will need to be updated to include the vocab's identifier in the new Omeka instance. Of course, you'll need to make sure it's installed first.

In general, you want to make sure that the any vocabs and data types referenced by the exported templates will be available in the new Omeka instance. So before you upload any templates you should check that:

  • referenced vocabularies are already installed
  • modules used in defining data types are installed ( eg the Numeric Data Types module provides additional data types such as Timestamp for dates
  • any custom vocabularies (created using the Custom Vocab are installed, along with the module itself of course
  • the Value Suggest module is installed if the template includes references to the controlled vocabs it provides

OmekaAPIClient.prepare_template_payload[source]

OmekaAPIClient.prepare_template_payload(template_file)

Insert local property, class, and vocab identifiers into a resource template exported from Omeka so that it can be uploaded to the local instance.

Parameters:

  • template_file - path to a template exported from Omeka (str or pathlib Path)

Returns:

  • template payload with local identifiers inserted
omeka_auth = OmekaAPIClient(
    api_url='https://timsherratt.org/collections/api',
    key_identity=os.getenv('KEY_IDENTITY'), 
    key_credential=os.getenv('KEY_CREDENTIAL')
)
template_payload = omeka_auth.prepare_template_payload('templates/Person.json')

# Check the label
assert template_payload['o:label'] == 'Person'

# Check that there is a list of properties
assert len(template_payload['o:resource_template_property']) > 0

OmekaAPIClient.upload_template[source]

OmekaAPIClient.upload_template(template_payload)

Upload a template exported from an instance of Omeka to the current local instance.

Parameters:

  • template_payload - dict payload generated by prepare_template_payload

Return:

  • dict containing a JSON-LD representation of the uploaded template
existing_template = omeka_auth.get_template_by_label('Person')

# If there is we'll delete it
# Trying to upload a template with the same label as an existing template will generate an error
if existing_template:
    deleted = omeka_auth.delete_resource(existing_template['o:id'], 'resource_templates')

# Now we can add the new template
template_payload = omeka_auth.prepare_template_payload('templates/Person.json')
new_template = omeka_auth.upload_template(template_payload)

# Result should be a 'ResourceTemplate
assert new_template['@type'] == 'o:ResourceTemplate'

# Label should be 'Person'
assert new_template['o:label'] == 'Person'

# It should have properties
assert len(new_template['o:resource_template_property']) > 0

OmekaAPIClient.localise_custom_vocabs[source]

OmekaAPIClient.localise_custom_vocabs(data_types)

Check a list of data types for references to custom vocabs. If found, look for the local identifier of the custom vocab, and insert it into the data type information.

Parameters:

  • data_types - a list of data types from an exported template property

Returns:

  • list of datatypes with local identifiers
data_types = [{'name': 'customvocab:200000', 'label': "Date qualifiers"}]

# Localise!
localised_data_types = omeka_auth.localise_custom_vocabs(data_types)
print(localised_data_types)

# Localised data type should start with 'customvocab'
assert localised_data_types[0].startswith('customvocab:')

# The localised customvocab id should not be the same as the supplied one
assert localised_data_types[0] != data_types[0]['name']
['customvocab:1']

OmekaAPIClient.get_template_class_id[source]

OmekaAPIClient.get_template_class_id(template)

Get the local id of the resource class associated with the supplied template.

Parameters:

  • template - dict from exported template

Returns:

  • class identifier
template = json.loads(Path('templates/Person.json').read_bytes())

person_class_id = omeka_auth.get_resource_by_term('schema:Person', 'resource_classes')['o:id']

# Get resource id
class_id = omeka_auth.get_template_class_id(template)

assert class_id == person_class_id

OmekaAPIClient.get_template_property_id[source]

OmekaAPIClient.get_template_property_id(template, term)

Get the local id of the property associated with the supplied template.

Parameters:

  • template - dict from exported template
  • term - property term (eg 'o:title_property')

Returns:

  • property identifier
template = json.loads(Path('templates/Person.json').read_bytes())

# get the id of the schema:name property
name_prop_id = omeka_auth.get_resource_by_term('schema:name', 'properties')['o:id']

# Get id of template property used for title
prop_id = omeka_auth.get_template_property_id(template, 'o:title_property')

# The ids should be the same
assert prop_id == name_prop_id

Utilities

OmekaAPIClient.format_resource_id[source]

OmekaAPIClient.format_resource_id(resource_id, resource_type)

Generate a formatted id for the resource with the specified Omeka id number and resource type.

Parameters:

  • resource_id - numeric identifier used by Omeka for this resource
  • resource_type - one of Omeka's resource types, eg: 'items', 'properties'

Returns:

  • a dict with values for '@id' and 'o:id'
id_url = omeka.format_resource_id(5, 'resource_templates')

assert id_url == {
    '@id': 'http://timsherratt.org/collections/api/resource_templates/5',
    'o:id': 5
}

OmekaAPIClient.prepare_property_value[source]

OmekaAPIClient.prepare_property_value(value, property_id)

Formats a property value according to its datatype as expected by Omeka. The formatted value can be used in a payload to create a new item.

Parameters:

  • value - a dict containing a value and (optionally) a type
  • property_id - the numeric identifier of the property

Note that is no type is supplied, 'literal' will be used by default.

Returns:

  • a dict with values for property_id, type, and either @id or @value.
prop_id = omeka_auth.get_property_id('schema:url')
prop_value = {'value': 'https://glam-workbench.net', 'type': 'uri'}

formatted_prop = omeka_auth.prepare_property_value(prop_value, prop_id)
formatted_prop
{'property_id': 393, 'type': 'uri', '@id': 'https://glam-workbench.net'}
assert prop_id == formatted_prop['property_id']
assert 'type' in formatted_prop
assert formatted_prop['@id'] == 'https://glam-workbench.net'

OmekaAPIClient.get_template_properties[source]

OmekaAPIClient.get_template_properties(template_id)

List properties used by the specified template.

The resource template objects returned by the API don't include property terms. This function gets the additional details, and organises the properties in a dictionary, organised by term. This makes it easy to check if a particular term is used by a template.

Parameters:

  • template_id - numeric identifier for a template

Returns:

  • a dict organised by property terms, with values for property_id and type
template_id = omeka_auth.get_template_by_label('Newspaper')['o:id']
newspaper_properties = omeka_auth.get_template_properties(template_id)

assert 'schema:name' in newspaper_properties

Example: adding a newspaper article from Trove

In the example below I'm going to manually step through the process of adding a new item to Omeka using the API in order to demonstrate the methods available. But of course the point of using the API is to automate such processes -- joining together the individual steps so they can be embedded into your own systems or workflows. For a more detailed example that uploads Trove newspaper articles from a variety of sources, including Trove searches, Trove lists, and Zotero libraries, see the GLAM Workbench.

Let's suppose we want to add this newspaper article in Trove to our Omeka instance. To take best advantage of Omeka's linked data infrastructure, we'll actually create two resources -- one for the article, and one for the newspaper it was published in.

I've already created templates labelled 'Newspaper' and 'Newspaper article'.

Let's start with the newspaper. First we need to find out the numeric identifier Omeka is using for the Newspaper template. We can use OmekaAPIClient.get_template_by_label to find out.

omeka_auth = OmekaAPIClient(
    api_url='http://timsherratt.org/collections/api',
    key_identity=os.getenv('KEY_IDENTITY'), 
    key_credential=os.getenv('KEY_CREDENTIAL')
)

newspaper_template_id = omeka_auth.get_template_by_label('Newspaper')['o:id']
newspaper_template_id
5

For convenience, we can get a summary of the properties used in the Newspaper template using OmekaAPIClient.get_template_properties. This is useful if we want to check which properties are in use, and what data types are expected.

omeka_auth.get_template_properties(newspaper_template_id)
{'schema:name': {'property_id': 1116, 'type': ['literal']},
 'schema:additionalType': {'property_id': 1199, 'type': ['uri']},
 'schema:description': {'property_id': 528,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:alternateName': {'property_id': 282,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:editor': {'property_id': 752, 'type': ['resource:item']},
 'schema:publisher': {'property_id': 967, 'type': ['resource:item']},
 'schema:issn': {'property_id': 931,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:startDate': {'property_id': 513, 'type': ['numeric:timestamp']},
 'schema:endDate': {'property_id': 657, 'type': ['numeric:timestamp']},
 'schema:locationCreated': {'property_id': 706, 'type': ['resource:item']},
 'schema:hasPart': {'property_id': 1405, 'type': ['resource:item']},
 'schema:about': {'property_id': 1392, 'type': ['resource:item']},
 'schema:mentions': {'property_id': 747, 'type': ['resource:item']},
 'schema:contentLocation': {'property_id': 1419, 'type': ['resource:item']},
 'schema:temporalCoverage': {'property_id': 460,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:subjectOf': {'property_id': 1391, 'type': ['resource:item']},
 'schema:url': {'property_id': 393, 'type': ['uri']},
 'schema:image': {'property_id': 742, 'type': ['resource:item']},
 'schema:identifier': {'property_id': 190,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:sameAs': {'property_id': 246, 'type': ['uri']}}

The first step in preparing our data for upload is to create a dictionary, using the required property terms as keys. In this case, we'll assign data about the newspaper to schema.name and schema.url.

newspaper = {
    'schema.name': [
        {
            'type': 'literal',
            'value': 'The Bendigo Independent (Vic. : 1891 - 1918)'
        }
    ],
    'schema:url': [
        {
            'type': 'literal',
            'value': 'http://nla.gov.au/nla.news-title806'
        }
    ]
}

Now we can use this data to create a payload for upload to Omeka. OmekaAPIClient.prepare_item_payload_using_template will check our data against the Newspaper template and build the payload.

payload = omeka_auth.prepare_item_payload_using_template(newspaper, newspaper_template_id)
Term schema.name not in template
Data type "literal" for term "schema:url" not allowed by template

Whoops! It seems we have some problems with our data file! First of all we've used a full stop, rather than a colon in schema:name. Second, we've said the data type of schema:url is 'literal', but if we check the template properties we'll see it' should be 'uri'. Let's make these changes.

newspaper = {
    'schema:name': [
        {
            'type': 'literal',
            'value': 'The Bendigo Independent (Vic. : 1891 - 1918)'
        }
    ],
    'schema:url': [
        {
            'type': 'uri',
            'value': 'http://nla.gov.au/nla.news-title806'
        }
    ]
}
payload = omeka_auth.prepare_item_payload_using_template(newspaper, newspaper_template_id)

That seems better! Now we can examine the payload.

payload
{'schema:name': [{'property_id': 1116,
   'type': 'literal',
   '@value': 'The Bendigo Independent (Vic. : 1891 - 1918)'}],
 'schema:url': [{'property_id': 393,
   'type': 'uri',
   '@id': 'http://nla.gov.au/nla.news-title806'}]}

Notice how the values have been reformatted? They should now be ready to upload to Omeka using OmekaAPIClient.add_item. We'll supply both the payload and the newspaper template id.

newspaper_item = omeka_auth.add_item(payload, template_id=newspaper_template_id)

We can check the contents of newspaper_item to make sure it's been added succesfully.

newspaper_item
{'@context': 'http://timsherratt.org/collections/api-context',
 '@id': 'http://timsherratt.org/collections/api/items/1045',
 '@type': ['o:Item', 'schema:Newspaper'],
 'o:id': 1045,
 'o:is_public': True,
 'o:owner': {'@id': 'http://timsherratt.org/collections/api/users/1',
  'o:id': 1},
 'o:resource_class': {'@id': 'http://timsherratt.org/collections/api/resource_classes/161',
  'o:id': 161},
 'o:resource_template': {'@id': 'http://timsherratt.org/collections/api/resource_templates/5',
  'o:id': 5},
 'o:thumbnail': None,
 'o:title': 'The Bendigo Independent (Vic. : 1891 - 1918)',
 'thumbnail_display_urls': {'large': None, 'medium': None, 'square': None},
 'o:created': {'@value': '2022-04-04T00:48:33+00:00',
  '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},
 'o:modified': {'@value': '2022-04-04T00:48:33+00:00',
  '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},
 'o:media': [],
 'o:item_set': [],
 'o:site': [],
 'schema:name': [{'type': 'literal',
   'property_id': 1116,
   'property_label': 'name',
   'is_public': True,
   '@value': 'The Bendigo Independent (Vic. : 1891 - 1918)'}],
 'schema:url': [{'type': 'uri',
   'property_id': 393,
   'property_label': 'url',
   'is_public': True,
   '@id': 'http://nla.gov.au/nla.news-title806'}]}

Great! Now what about the article? Again let's start by having a look at the 'Newspaper article' template.

article_template_id = omeka_auth.get_template_by_label('Newspaper article')['o:id']
omeka_auth.get_template_properties(article_template_id)
{'schema:name': {'property_id': 1116,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:additionalType': {'property_id': 1199, 'type': ['uri']},
 'schema:description': {'property_id': 528,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:alternateName': {'property_id': 282,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:datePublished': {'property_id': 928, 'type': ['numeric:timestamp']},
 'schema:pagination': {'property_id': 376,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:creator': {'property_id': 329, 'type': ['resource:item']},
 'schema:contributor': {'property_id': 1303, 'type': ['resource:item']},
 'schema:isPartOf': {'property_id': 736, 'type': ['resource:item']},
 'schema:license': {'property_id': 1348,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:about': {'property_id': 1392, 'type': ['resource:item']},
 'schema:mentions': {'property_id': 747, 'type': ['resource:item']},
 'schema:contentLocation': {'property_id': 1419, 'type': ['resource:item']},
 'schema:temporalCoverage': {'property_id': 460,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:subjectOf': {'property_id': 1391, 'type': ['resource:item']},
 'schema:image': {'property_id': 742, 'type': ['resource:item']},
 'schema:url': {'property_id': 393, 'type': ['uri']},
 'schema:identifier': {'property_id': 190,
  'type': ['literal', 'uri', 'resource:item']},
 'schema:sameAs': {'property_id': 246, 'type': ['uri']},
 'schema:text': {'property_id': 833,
  'type': ['literal', 'uri', 'resource:item']}}

This time we'll build our data file in stages.

article = {}

# Add value for schema:name
article['schema:name'] = ["MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD."]

You'll notice that this time I've only included the value of the property, not the data type. This is because OmekaAPIClient.prepare_item_payload_using_template will insert default data types if they're not specified. The basic rules it uses if you don't supply a data type are:

  • if the template defines a default data type, use that
  • if 'literal' is in the template's list of expected data types, use that
  • if 'literal' is not in the template's list of expected data types print a warning asking the user to specify a data type and drop the property from the payload

In the case above, the 'literal' data type will be assigned to the schema:name value.

To create a link between the article and the newspaper it was published in, we can use schema.isPartOf. If we look in the list of template properties we see that this property expects a data type of 'resource:item'.

'schema:isPartOf': {'property_id': 736, 'type': ['resource:item']}

The 'resource:item' data type means that the value will be an identifier pointing to another Omeka item. So we include the identifier of the newly-created newspaper record. Once again, the data type will be automatically added when we generate the payload.

article['schema:isPartOf'] = [newspaper_item['o:id']]

Next we'll add the publication date. To recognise dates as specific data types, you need to install the Numeric Data Types module. Once that's done, you can set the 'numeric:timestamp' data type as the default for any date fields in your template. In the list of properties from the newspaper article template, you can see:

'schema:datePublished': {'property_id': 928, 'type': ['numeric:timestamp']}

The date value itself is supplied in a standard ISO format -- 'YYYY-MM-DD'.

article['schema:datePublished'] = ['1918-03-14']

Finally we'll add a link to the article. Once again the template includes a default data type.

'schema:url': {'property_id': 393, 'type': ['uri']}

So we can just include the value.

article['schema:url'] = ['http://nla.gov.au/nla.news-article226799674']

Now that we've assembled the article metadata, we can generate a payload.

article_payload = omeka_auth.prepare_item_payload_using_template(article, article_template_id)

As you can see below, the default data types have been inserted into the payload, and some additional fields have been added to define the link to the newspaper item.

article_payload
{'schema:name': [{'property_id': 1116,
   'type': 'literal',
   '@value': "MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD."}],
 'schema:isPartOf': [{'property_id': 736,
   'type': 'resource:item',
   '@id': 'http://timsherratt.org/collections/api/items/1045',
   'value_resource_id': 1045,
   'value_resource_name': 'items'}],
 'schema:datePublished': [{'property_id': 928,
   'type': 'numeric:timestamp',
   '@value': '1918-03-14'}],
 'schema:url': [{'property_id': 393,
   'type': 'uri',
   '@id': 'http://nla.gov.au/nla.news-article226799674'}]}

We could now go ahead and upload the payload to Omeka, but what if we want to include media files? In this case I have a JPG image of the article I want to attach. All you need to do is supply a list of paths pointing to media files using the media_files parameter. The list can just include the paths as strings, in which case the file name will be used as the media object's title. Alternatively, you can supply a list of dicts, each containing a path and title value.

# The paths can be strings or pathlib Paths
media_files = ['media/nla.news-article226799674-24144902.jpg']

# Include the media files when we upload the payload
article_item = omeka_auth.add_item(article_payload, media_files=media_files, template_id=article_template_id)

When we look at the uploaded item, we'll see that the media files have been processed and added to the record.

article_item
{'@context': 'http://timsherratt.org/collections/api-context',
 '@id': 'http://timsherratt.org/collections/api/items/1046',
 '@type': ['o:Item', 'schema:NewsArticle'],
 'o:id': 1046,
 'o:is_public': True,
 'o:owner': {'@id': 'http://timsherratt.org/collections/api/users/1',
  'o:id': 1},
 'o:resource_class': {'@id': 'http://timsherratt.org/collections/api/resource_classes/543',
  'o:id': 543},
 'o:resource_template': {'@id': 'http://timsherratt.org/collections/api/resource_templates/4',
  'o:id': 4},
 'o:thumbnail': None,
 'o:title': "MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD.",
 'thumbnail_display_urls': {'large': 'http://timsherratt.org/collections/files/large/c60918ee88cb729ae8803742bbbb185460700903.jpg',
  'medium': 'http://timsherratt.org/collections/files/medium/c60918ee88cb729ae8803742bbbb185460700903.jpg',
  'square': 'http://timsherratt.org/collections/files/square/c60918ee88cb729ae8803742bbbb185460700903.jpg'},
 'o:created': {'@value': '2022-04-04T00:48:40+00:00',
  '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},
 'o:modified': {'@value': '2022-04-04T00:48:40+00:00',
  '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},
 'o:media': [{'@id': 'http://timsherratt.org/collections/api/media/1047',
   'o:id': 1047}],
 'o:item_set': [],
 'o:site': [],
 'schema:name': [{'type': 'literal',
   'property_id': 1116,
   'property_label': 'name',
   'is_public': True,
   '@value': "MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD."}],
 'schema:datePublished': [{'type': 'numeric:timestamp',
   'property_id': 928,
   'property_label': 'datePublished',
   'is_public': True,
   '@value': '1918-03-14',
   '@type': 'http://www.w3.org/2001/XMLSchema#date'}],
 'schema:isPartOf': [{'type': 'resource:item',
   'property_id': 736,
   'property_label': 'isPartOf',
   'is_public': True,
   '@id': 'http://timsherratt.org/collections/api/items/1045',
   'value_resource_id': 1045,
   'value_resource_name': 'items',
   'url': None,
   'display_title': 'The Bendigo Independent (Vic. : 1891 - 1918)'}],
 'schema:url': [{'type': 'uri',
   'property_id': 393,
   'property_label': 'url',
   'is_public': True,
   '@id': 'http://nla.gov.au/nla.news-article226799674'}]}