Organizing Content

This section explains how to use the Connect Server APIs to organize your content using tags and vanity URLs. See the Deploying Content section for help creating and deploying content, and the Managing Content section for help discovering and managing existing content.

Note

These recipes use bash snippets and rely on curl to perform HTTP requests. These recipes also use the CONNECT_SERVER and CONNECT_API_KEY environment variables introduced in the Getting Started section of this cookbook.

Tags

You can organize your content on Connect using a hierarchy of labels called tags. Tags and content items have a many-to-many relationship: any content item may be associated with multiple tags, and any tag may be associated with multiple content items. This gives you the flexibility to group and organize your content in whatever way best suits your organization.

Important

Creating, updating, and deleting tags require administrator permissions. However, assigning and unassigning tags to content items only requires owner or collaborator permissions on the content item.

You can find the full reference of tag-related API endpoints in the Posit Connect API Reference.

Creating a tag

This example creates a new hierarchy of tags for a hypothetical finance department to track their daily reports. First, create a “Finance” tag:

export DATA='{"name": "Finance"}'
curl --silent --show-error -L --max-redirs 0 --fail -X POST \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    --data "${DATA}" \
    "${CONNECT_SERVER}__api__/v1/tags"
# => {
# =>   "id": "14",
# =>   "name": "Finance",
# =>   "parent_id": null,
# =>   ...
# => }

Next, create another tag named “Daily” under the “Finance” tag by specifying the parent_id with the “Finance” tag’s id:

export DATA='{"name": "Daily", "parent_id": "14"}'
curl --silent --show-error -L --max-redirs 0 --fail -X POST \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    --data "${DATA}" \
    "${CONNECT_SERVER}__api__/v1/tags"
# => {
# =>   "id": "15",
# =>   "name": "Daily",
# =>   "parent_id": "14",
# =>   ...
# => }

Finding a tag

You can search for a tag by id using the GET /v1/tags/{id} endpoint:

curl --silent --show-error -L --max-redirs 0 --fail -X GET \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/tags/15"
# => {
# =>   "id": "15",
# =>   "name": "Daily",
# =>   "parent_id": "14",
# =>   ...
# => }

If you do not know the id of the tag but do know the hierarchy of names for the tag, then you can also search by that path (which should be comma-separated) instead of id. For example:

curl --silent --show-error -L --max-redirs 0 --fail -X GET \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/tags/Finance,Daily"
# => {
# =>   "id": "15",
# =>   "name": "Daily",
# =>   "parent_id": "14",
# =>   ...
# => }

Assigning a tag to a content item

You can easily assign tags to content items using the POST /v1/content/{guid}/tags endpoint. To assign the “Daily” tag to a content item:

Note

When assigning tags to content, all tags above the specified tag in the hierarchy are automatically also associated with the content item. For example, if you have “Finance” -> “Daily” as tags, and then assign the Daily tag to a content item, that content item will also be associated with the Finance tag.

export DATA='{"tag_id": "15"}'
curl --silent --show-error -L --max-redirs 0 --fail -X POST \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    --data "${DATA}" \
    "${CONNECT_SERVER}__api__/v1/content/ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5/tags"
# =>

A successful request returns a 200 HTTP status code with an empty response.

Listing content associated with tags

You can see what content is associated with a given tag using the GET /v1/tags/{id}/content endpoint.

curl --silent --show-error -L --max-redirs 0 --fail -X GET \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/tags/15/content"
# => [
# =>   {
# =>     "guid": "ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5",
# =>     "name": "shakespeare",
# =>     "title": "Shakespeare Word Clouds",
# =>     ...
# =>   }
# => ]

Listing tags associated with content

Likewise, you can see what tags are associated with a given content item using the GET /v1/content/{guid}/tags endpoint.

curl --silent --show-error -L --max-redirs 0 --fail -X GET \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/content/ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5/tags"
# => [
# =>   {
# =>     "id": "14",
# =>     "name": "Finance",
# =>     "parent_id": null,
# =>     ...
# =>   },
# =>   {
# =>     "id": "15",
# =>     "name": "Daily",
# =>     "parent_id": "14",
# =>     ...
# =>   }
# => ]

Vanity URLs

Vanity URLs allow you to assign custom paths to content items, providing more memorable and descriptive paths to your popular content items. Vanity URLs also let you take advantage of advanced deployment strategies such as Blue-Green Deployments.

You can find the full reference of vanity-related API endpoints in the Posit Connect API Reference.

Setting a vanity URL for a content item

If you’d like to set a vanity URL for a specific content item, you should use the PUT /v1/content/{guid}/vanity endpoint.

Note

A content item can only have one vanity URL. Likewise, a unique vanity URL can only correspond to one content item. If you’d like to re-assign a vanity URL within a single API call, you can use the force parameter as outlined in the API Reference docs.

export DATA='{"path": "/shakespeare/"}'
curl --silent --show-error -L --max-redirs 0 --fail -X PUT \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    --data "${DATA}" \
    "${CONNECT_SERVER}__api__/v1/content/ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5/vanity"
# => {
# =>   "content_guid": "ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5",
# =>   "path": "/shakespeare/",
# =>   ...
# => }

Getting a vanity URL for a content item

You can easily fetch the vanity URL for a specific content item using the GET /v1/content/{guid}/vanity endpoint.

curl --silent --show-error -L --max-redirs 0 --fail -X GET \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/content/ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5/vanity"
# => {
# =>   "content_guid": "ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5",
# =>   "path": "/shakespeare/",
# =>   ...
# => }

If there is no vanity URL set, you will receive a 404 HTTP status code.

Removing a vanity URL from a content item

You can remove a vanity URL from a content item using the DELETE /v1/content/{guid}/vanity endpoint.

curl --silent --show-error -L --max-redirs 0 --fail -X DELETE \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/content/ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5/vanity"
# =>

A successful request returns a 204 HTTP status code with an empty response.

Listing all vanity URLs

Lastly, you might want to list all vanity URLs across all content on the Connect server. This can be useful for auditing or searching for content by URL. The GET /v1/vanities endpoint provides this functionality.

curl --silent --show-error -L --max-redirs 0 --fail -X GET \
    -H "Authorization: Key ${CONNECT_API_KEY}" \
    "${CONNECT_SERVER}__api__/v1/vanities"
# => [
# =>   {
# =>     "content_guid": "ccbd1a41-90a0-4b7b-89c7-16dd9ad47eb5",
# =>     "path": "/shakespeare/",
# =>     ...
# =>   },
# =>   ...
# => ]