How do I update or add a controlled vocabulary metadata value through the DAM API?

  • Last updated
  • 1 minute read

Goal

Update asset metadata with controlled vocabulary with the DAM API.

Overview

When building a custom API integration for the Widen Collective®, it’s common to create a controlled vocabulary metadata field with values that update through the Widen API. This means asset metadata is synced with another system or updates automatically based on an external event or trigger.

Free text metadata fields can be updated using our Update Metadata API endpoint by itself. For controlled vocabulary metadata fields, you will need to perform some additional steps, including when you want to update a field to a value that does not already exist.

Some programmatic logic is required to perform this operation. The code examples in this article demonstrate the general steps involved. They are written in Python since it is a popular language used for consuming APIs, but the examples can be easily translated to other programming languages.

  1. Updating metadata through the API

    First, set up some variables for authentication headers in order to make requests to the API:

    auth_token = 'YOUR_TOKEN_HERE'
    headers = {
       'Authorization': f"Bearer {auth_token}"
    }

    In this example, we are using bearer authorization as described in the API documentation. Then, a dictionary is created containing header names mapped to header values to make it easy to pass the correct authorization header in our API requests without repeating ourselves. In the code examples, you will need to replace YOUR_TOKEN_HERE with your own API token for your DAM.

    Now that authentication is in place, you can start making API calls. In our example scenario, you want to update the metadata on an asset in your DAM programmatically, so start with this basic example:

    import requests
    
    asset_id = 'YOUR_ASSET_ID'
    
    response = requests.put(
     f"https://api.widencollective.com/v2/assets/{asset_id}/metadata",
     headers=headers, # pass in auth header created earlier
     json={
       'fields': { # metadata values we want to set
         'description': ['A delicious cake.'],
         'flavors': ['vanilla', 'strawberry']
       }
     }
    )
    response.raise_for_status()

    Here we are importing the popular Requests library for Python in order to issue HTTP requests to the API. There are many other HTTP clients that can be used as well, but Requests has a simple interface that  helps to demonstrate the program logic concisely. Make an HTTP PUT request by calling the requests.put function, and specify a JSON request body using the json parameter. Finally, call the raise_for_status method on the response to ensure an exception is raised if a non-successful HTTP status code is returned by the API; otherwise Requests will ignore failed API calls. Check the Requests documentation for more information on how to use Requests.

    In the example above, we are issuing a PUT request to the Update Metadata endpoint to set new values for both a description and a flavors field. These field names refer to the display key of the metadata fields you want to set. You can see display keys using the Fields Viewable endpoint. These will vary within your own DAM depending on how your metadata fields are configured.

    If both of these fields were free text field types then this API call would be successful, and the asset metadata would be updated. Other field types have more strict validation on the values they allow, so for this example, the flavors field is set up to be a checkbox group field. This field type has controlled vocabulary and allows the user to select zero, one, or multiple values to apply to an asset, as long as all the values are listed in the field’s controlled vocabulary.

    This field is initially set up containing only the values vanilla and chocolate in its controlled vocabulary. Since strawberry is not in that list and is in the request, you will get the following error response back from the API when you try to make this call:

    {
     "error": true,
     "response_code": 404,
     "error_message": "The metadata value '[vanilla, strawberry]' is not valid for this Checkbox Group field. One or more of the values are not in the metadata field's vocabulary."
    }

    This error is returned because the API validated the values given against the flavors field’s controlled vocabulary and found that the value strawberry was not approved for that field. This is a benefit of controlled vocabulary fields, as it allows DAM admins to ensure that only approved values are set for the field to enforce consistent naming across the site, regardless of whether the metadata comes from a user or an API integration.

    However, you might not always want this behavior in an integration. If you are updating metadata from an external system that holds the source of truth for a particular metadata field, then you may want to add new values to the controlled vocabulary list automatically.

  2. Adding a new value to the field vocabulary

    To set the field to a new value not in the field’s controlled vocabulary list, first verify that the value you want to set is contained in the field’s vocabulary.If it is not present, add it to the list. First, use the List Values endpoint to get all values belonging to the field’s vocabulary:

    response = requests.get(
     'https://api.widencollective.com/v2/metadata/flavors/vocabulary',
     headers=headers
    )
    response.raise_for_status()
    allowed_values = response.json()['vocabulary']

    If successful, this API call will return a JSON response like this:

    {
     "vocabulary": [
       "vanilla",
       "chocolate"
     ],
     "_links": {
       "self": "https://api.widencollective.com/v2/metadata/flavors/vocabulary"
     }
    }

    Since the response data is encoded as a JSON object, you can use the json helper method provided by Requests to easily deserialize the response and access the vocabulary list:

    vocabulary = response.json()['vocabulary']

    After being deserialized, the list from the response can be used to check to see if the value strawberry is already contained within the vocabulary. If not, then make another API call to add it to the list. Then you can perform your asset metadata update. Since vocabulary values are case-insensitive, you must first check if the desired value is contained in the list in a case-insensitive way. Python provides an easy way of doing this:

    if not 'strawberry'.casefold() in (value.casefold() for value in vocabulary):
     response = requests.post(
       'https://api.widencollective.com/v2/metadata/flavors/vocabulary',
       headers=headers,
       json={'value': 'strawberry'}
     )
     response.raise_for_status()

    If the code finds that the value strawberry is not already in the controlled vocabulary, it issues an API call to the Add Value endpoint with the new value in the request. This API call will allow you to set the flavors field to this new value on an asset. Keep in mind that the user connected to your API token will need additional permissions in one of its assigned roles to update a field’s controlled vocabulary.

    If successful, your new value will now be allowed and you can issue the original metadata update request successfully. This isn’t required to make the update, but you can verify that the new value is added to the vocabulary list by calling the List Values endpoint again:

    {
     "vocabulary": [
       "vanilla",	
       "chocolate",
       "strawberry"
     ],
     "_links": {
       "self": "https://api.widencollective.com/v2/metadata/flavors/vocabulary"
     }
    }

    The Add Value endpoint will return an error code if you try to add a value that already exists in the target field’s vocabulary, so checking the presence of the field using the List Values can be helpful.

    Finally, issue the metadata update request:

    response = requests.put(
     f"https://api.widencollective.com/v2/assets/{asset_id}/metadata",
     headers=headers,
     json={
       'fields': {
         'flavors': [
           'vanilla',
           'strawberry'
         ]
       }
     }
    )
    response.raise_for_status()

    A response with a status code of 200 indicates your vocabulary update was correct and the asset now has the right metadata applied to it.

    If you are setting multiple field values that have controlled vocabulary, you may need to repeat the vocabulary update process multiple times for each field you want updated. You can also check out our other endpoints related to controlled vocabulary available in our API.

  3. Full code example

    Below is the full example Python program for reference, combining all of the steps for updating metadata values. To reduce duplication the metadata strings have been made into variables.

    import requests
    
    asset_id = 'YOUR_ASSET_ID'
    field_key = 'flavors'
    field_value = 'strawberry'
    
    # Set API token and auth header.
    auth_token = 'YOUR_TOKEN_HERE'
    headers = {
      'Authorization': f"Bearer {auth_token}"
    }
    
    # Get the current list of valid values for the controlled vocabulary metadata
    # field.
    response = requests.get(
     f"https://api.widencollective.com/v2/metadata/{field_key}/vocabulary",
     headers=headers
    )
    # Ensure we validate HTTP status code.
    response.raise_for_status()
    
    # Check if our desired value is already allowed. Values are case-insensitive, so
    # we are using `casefold` to check if the desired value is in the list in a case-
    # insensitive manner.
    vocabulary = response.json()['vocabulary']
    if not field_value.casefold() in (value.casefold() for value in vocabulary):
     # The value is not already in the controlled  vocabulary list, so issue a
     # request to add it. If the value was already present, a 400 error would be
     # returned.
     response = requests.post(
       f"https://api.widencollective.com/v2/metadata/{field_key}/vocabulary",
       headers=headers,
       json={'value': field_value}
     )
     response.raise_for_status()
     
    # Finally, we can update the metadata of an asset with our new vocabulary value.
    response = requests.put(
     f"https://api.widencollective.com/v2/assets/{asset_id}/metadata",
     headers=headers,
     json={
       'fields': {
         'description': ['A delicious cake.'],
         'flavors': ['vanilla', 'strawberry']
       }
     }
    )
    response.raise_for_status()