Loading...
Loading...
Loading...
Loading...
How to use member authorization with the Delivery API to access protected content.
Loading...
Loading...
Loading...
Loading...
Learn how to extend the Content Delivery API with custom selecting, filtering, and sorting options for the multi-item-based endpoint.
The Delivery API allows you to retrieve multiple items by utilizing the /umbraco/delivery/api/v2/content
endpoint. With the built-in query parameters, you have the flexibility to get any number of content nodes based on your needs. For a comprehensive list of supported query options, please refer to the Endpoints section.
For the query endpoint, we have created a new Examine index (DeliveryApiContentIndex) that facilitates fast retrieval of the desired content. This index ensures quick indexing and searching of data, with the possibility for future extensions.
In this article, we'll explore creating custom selecting, filtering, and sorting options to enhance the querying capabilities of the Delivery API.
Let's take a look at an example of using the query endpoint with query parameters for fetch
, filter
, and sort
. A request might look like this:
The placeholders in the example (xxx
, yyy
, etc.) represent the values that each query option evaluates in order to determine the suitable query handler.
You can include only one fetch
parameter, while multiple filter
and sort
parameters are allowed. Additionally, the order of the sort
parameters influences the sorting behaviour. Refer to the Query parameters section for the currently supported options.
The implementation of each querying option consists of a class for indexing the data into the DeliveryApiContentIndex and another one for handling the query. By implementing the IContentIndexHandler
interface, you can control how your relevant data is indexed and made available for querying through our index. And you can customize the querying behaviour to suit your needs by implementing the ISelectorHandler
, IFilterHandler
, and ISortHandler
interfaces.
In the following sections, we will explore the implementation details of creating custom querying functionality for the Delivery API.
Selectors handle the fetch
part of a query.
To showcase how to build a custom selector, consider a site structure with a few blog posts. A post is linked to an author, which is another content item.
Authors can be marked as 'Featured' using a toggle, granting them additional visibility and recognition. We will use this marker as part of the indexing implementation for our selector option.
The following example demonstrates the implementation of an AuthorSelector
, which allows you to customize the querying behaviour specifically for finding all featured authors. This class contains both indexing and querying responsibilities. However, keep in mind that it is generally recommended to separate these responsibilities into dedicated classes.
The AuthorSelector
class implements the ISelectorHandler
and IContentIndexHandler
interfaces.
ISelectorHandler
allows for handling the fetch
value in API queries through the CanHandle()
and BuildSelectorOption()
methods.
CanHandle()
determines if the given fetch
query corresponds to the "featuredAuthors"
value.
BuildSelectorOption()
constructs the selector option to search for authors with a positive value (for example, "y"
) in a "featured"
index field.
The GetFields()
and GetFieldValues()
methods each play a role in defining how the data should be indexed and made searchable.
GetFields()
defines the behaviour of fields that are added to the index. In this example, the "featured"
field is added as a "raw" string for efficient and accurate searching.
GetFieldValues()
is responsible for retrieving the values of the defined index fields. In this case, the "featured"
field of content items of type "author"
. It creates an IndexFieldValue
with the appropriate field value ("y"
for featured, "n"
otherwise), which will be added to the index.
Since our custom query option modifies the index structure, we will need to rebuild the DeliveryApiContentIndex. You can find it by navigating to the "Examine Management" dashboard in the "Settings" section. Once rebuilt, we can make a request to the Delivery API query endpoint as follows:
Request
Response
Filters handle the filter
part of a query.
Staying within the topic of blog posts and their authors, we will create a custom filter to find posts by specific author(s).
This filter allows specifying the desired author(s) by their key (Guid
) in an author:
filter option. Multiple authors can be included by listing their keys as comma-separated-values, like:
Request
The response will include the blog posts associated with the provided authors, enabling us to retrieve only the relevant results from the API.
Response
Our filter implementation follows a similar structure to the custom selector we discussed earlier. We continue to utilize the IContentIndexHandler
interface, but this time we introduce the IFilterHandler
. This combination gives us flexibility and control over the filtering behaviour.
The procedure remains the same - we store and query the author key in a new "authorId"
field within the index. Consequently, we will need to rebuild the index to reflect the changes.
To illustrate the implementation, consider the following code example:
The principal difference from the selector is that the filter implements BuildFilterOption()
instead of BuildSelectorOption()
. Here, the filter performs an exact match for any specified Guid
in the query. Efficiently, this makes the filter perform an OR
operation against the index.
Since we need to perform an exact match, the index field (authorId
) is once again defined as a "raw" string. Other options include "analyzed" and "sortable" strings. These support "contains" searches and alpha-numeric sorting, respectively.
When implementing a filter, you can use the following operators: Is
, IsNot
, Contains
, DoesNotContain
, GreaterThan
, GreaterThanOrEqual
, LessThan
and LessThanOrEqual
.
The range operators (the latter four) only work with number and date fields - FieldType.Number
and FieldType.Date
respectively.
It is possible to pass multiple values to each operator, and these values will be treated inclusively as an or operator. For example, if tag1
and tag2
were passed into a filter using the Is
operator, any document containing either tag1
or tag2
would return. The request for this might look like this:
If you require this functionality to be restrictive i.e. tag1
and tag2
, then the current approach would be to chain the custom filter. The request would change to look more like this:
Finally, we can also add custom handling for the sort
part of the query.
We'll add a custom sort handler that allows us to sort blog posts based on a custom "publishDate"
Date Picker property. The implementation will allow for sorting the posts in ascending or descending order.
This sorting should only be used with query results that have a published date to ensure accurate results.
To demonstrate this, consider the following implementation example:
The implementation follows the same structure as the other examples, defined by the IContentIndexHandler
and ISortHandler
interfaces.
One point to highlight is that we store the "publishDate"
value as a "date" field in the index, which allows for correct date sorting.
Once more, when adding fields to the index, we need to rebuild it to reflect the changes.
In the following example request, we also apply the author filter to retrieve only "blogpost"
content nodes, which we know have the "publishDate"
field.
Request
Response
Boosting Delivery API performance with output caching.
In many cases the Delivery API output is stateless, and it is not absolutely necessary to push content updates immediately. In these cases the API can greatly benefit from using output caching.
Output caching is an opt-in feature in the Delivery API. It can be configured individually for both the Content and Media Delivery APIs. When enabled, API outputs are cached on the server for each unique request, and re-used until the cache expires.
Under the hood, the Delivery API utilizes the built-in output caching middleware in ASP.NET Core to handle the cache.
Output caching is primarily designed to increase performance. While the Delivery API is performant on its own, output caching takes the performance to another level.
Another aspect to consider is the overall server load. Uncached requests require much more processing time than cached requests. Especially for high traffic sites, even a short-lived output cache makes a significant difference in the server load. This might result in a lesser need to scale instances, and thus a greener footprint for the site.
However, output caching does come with a few trade-offs:
The cache lives in memory by default. This means the site will consume additional memory to handle the cache.
The cache does not expire automatically when content changes. Therefore, editors will experience increased publishing time when making changes to existing content.
Requests made in preview mode are not subject to output caching.
Output caching can be a bad fit in some cases:
If editors require immediate publishing of content updates (see above).
When using personalization in the API output.
If a custom property editor requires re-rendering for every request (for example if a property value converter outputs the current time).
Output caching must be explicitly enabled by configuration. To enable it, add the OutputCache
section to the DeliveryApi
configuration in appsettings.json
:
The output cache duration (time-to-live) can be configured for the Content and Media Delivery APIs. In the example above, content output is cached for 15 minutes while media output is cached for an hour.
The default output caching mechanism is based on the individual server instance memory. When hosting in a load balanced environment, this likely will not work, as the memory cache isn't synchronized across instances.
Instead you'll need to use a distributed caching solution like Redis cache. Starting with .NET 8, Microsoft supports output caching with Redis cache as backing store. Read more here.
While output caching is a great way to boost performance, it should never be used as a band-aid to solve poor uncached performance. The Delivery API is generally performant without caching.
If you experience performance issues while querying the Delivery API, your first step should be to diagnose and fix the root cause. This could be any number of things, like:
Un-performant value converters.
Overly complex queries.
An inexpedient content architecture.
...or something else entirely.
Hiding such problems behind output caching should only ever be considered as a short-term solution. In the long run it will not be a sustainable fix.
Using property expansion and limiting to shape the Delivery API output
This article explains the mechanics of property expansion and limiting in depth. If you haven't already, please read the Getting started article first - in particular the "Concepts" section.
Property expansion and limiting applies only to select property editors. The following built-in property editors in Umbraco support expansion and limiting:
Picker editors
Content Picker
Media Picker
Media Picker (legacy)
Multinode Treepicker
Block-based editors
Block List
Block Grid
Rich Text Editor (with blocks)
When working with property expansion and limiting in API queries, there are two rules of thumb to keep in mind:
Expandable properties are not expanded by default. They must be expanded explicitly.
All properties are included in the API output by default. We can apply limiting to limit the included properties.
In the following examples, we will be querying a content tree with blog posts and blog authors:
All blog posts are located under a root content item called "Posts".
All authors are located under a root content item called "Authors".
The blog post content type (post
) contains two properties that support expansion and limiting:
author
: A content picker for picking the author of the post.
coverImage
: A media picker for picking an image for the post.
The author content type (author
) contains a single property that supports expansion and limiting:
picture
: A media picker for picking a picture of the author.
When fetching a blog post, the author
and coverImage
properties are returned in their un-expanded representation by default. This representation does not contain any property data; the properties
collections of author
and coverImage
are empty:
Request
Response
If we want to show the author's picture when rendering the blog post, we need to expand the author
property. By expanding the property, the author properties (including picture
) are included in the output. We can achieve this by appending the expand
parameter to our request.
The expand
parameter syntax is as follows:
expand=properties[propertyAlias1,propertyAlias2,propertyAlias3]
Within the properties
part of the expand
parameter we can list the aliases of the properties we wish to expand. If we want to expand all expandable properties, we can use the operator $all
instead:
expand=properties[$all]
Request
Response
Now we have the picture
data in the properties
collection of author
. However, the rest of the author's properties (biography
and dateOfBirth
) are also present in our output, so we are slightly over-fetching. We will take care of that later.
First, we need to get the alt texts of our images (the blog post coverImage
and the author picture
). The alt text in this case is a text string property (altText
) on the media type. Fetching the alt texts is possible because property expansion can be performed both across multiple properties and in a nested fashion.
For nested property expansion, the expand
parameter syntax is as follows:
expand=properties[propertyAlias[properties[nestedPropertyAlias1,nestedPropertyAlias2]]]
Nested property expansion can also be combined with the $all
operator:
expand=properties[$all[properties[nestedPropertyAlias1,nestedPropertyAlias2]]]
There is no API limit to how "deep" the nesting can go. Eventually though, the total length of the request URL may become a hard limit to the size of the query.
Let's amend the expand
parameter to accommodate expansion of the images:
Request
Response
As mentioned above we are slightly over-fetching. We don't need all the author data - we are only interested in the author's picture
. To fix this we can apply property limiting by adding the fields
parameter to our request.
The fields
parameter allows us to limit the properties in the output to only those specified. The parameter uses the same syntax as the expand
parameter.
Our ideal blog post output contains:
All the properties of the blog post, including the altText
of the post coverImage
.
Only the picture
property of author
, including the altText
of the author picture
.
As with property expansion, we can use the $all
operator in the fields
parameter. This will include everything at any given query level. We'll use this to include all the blog post properties in the output without having to specify each property explicitly:
Request
Response
Now the API output contains only the properties we need to render the blog post.
Property limiting is particularly useful when querying multiple items. For example, if we were building a condensed list of blog posts, we likely wouldn't need the author data nor the blog post content. By applying limiting to a filtered query, we can tailor the API output specifically to this scenario:
Request
Response
If you are not familiar with block-based editors, please refer to this article for the general concepts of these.
In the API output, a block has little value without its contained properties. Therefore, the content and settings properties of blocks are always included in the output. However, these properties are not expanded. As such, we can apply expansion and limiting to the contained properties.
In the following examples we'll request different types of articles, all of which are located under a root content item called "Articles":
An article with a Block List property (blockList
).
An article with a Block Grid property (blockGrid
).
An article with a Rich Text Editor property (richText
).
All these properties are configured with a "Featured Post" block which consists of:
A content model (featuredPost
) that contains:
title
: A text string property.
post
: A content picker property that allows for picking a blog post.
A settings model (featuredPostSettings
) that contains:
backgroundColor
: An approved color property.
showTags
: A toggle property.
The goal is once again to build a condensed list of blog posts. But this time we'll build the list from the "Featured Post" blocks within each block editor.
To build the list we need the block title
, the coverImage
and excerpt
from the picked post, and the backgroundColor
from the block settings. Thus, we need to:
Expand the post
property to retrieve the altText
of the post coverImage
.
Limit both the block-level properties and the nested post
properties, as to only output the properties relevant for building the condensed list.
For comparison, the samples show both the default output and the output with expansion and limiting applied. Notice that:
The expand
and fields
parameter syntax is the same for all editors, even though their rendered output is structurally different.
The expand
and fields
parameters target both the content and settings parts of each block.
Default output without expansion and limiting:
Request
Response
Output with property expansion and limiting:
Request
Response
Default output without expansion and limiting:
Request
Response
Output with property expansion and limiting:
Request
Response
Request
Response
Output with property expansion and limiting:
Request
Response
Property expansion and limiting is a powerful feature that can boost our application performance. With this, we can prevent additional requests to obtain data for linked items, and we can tailor the output to specific use cases.
However, it is also a complex feature. The query syntax quickly gets complicated, particularly when targeting block editors. You will likely need to experiment to get the query exactly right. Hopefully, the examples in this article will guide you in applying expansion and limiting to your own content.
How to fetch protected content from the Delivery API with a server-to-server approach.
If protected content is consumed from the Delivery API in a server-to-server context, the interactive authorization flow won't work. Instead, we have to utilize the OpenId Connect Client Credentials flow, which is configured in the application settings.
In the Delivery API, Client Credentials map known Members to client IDs and secrets. These Members are known as API Members. When an API consumer uses the Client Credentials of an API Member, the consumer efficiently assumes the identity of this API Member.
An API Member works the same as a regular Member, with the added option of authorizing with Client Credentials.
In the following configuration example, the Member "member@local" is mapped to a set of Client Credentials:
After restarting the site, the backoffice will list "member@local" as an API Member:
The configured Client Credentials can be exchanged for an access token using the Delivery API token endpoint. Subsequently, the access token can be used as a Bearer token to retrieve protected content from the Delivery API.
The following code sample illustrates how this can be done.
This sample requires the NuGet packages Microsoft.Extensions.Hosting
and IdentityModel
to run.
You should always reuse access tokens for the duration of their lifetime. This will increase performance both for your Delivery API consumer and for the Delivery API itself.
The code sample handles token reuse in the ApiAccessTokenService
service. It must be registered as a singleton service to work.
In the code sample, the token endpoint is hardcoded in the token exchange request. The Delivery API also supports OpenId Connect Discovery for API Members, if you prefer that.
Get started with the Content Delivery API.
The Content Delivery API delivers headless capabilities built directly into Umbraco. It allows you to retrieve your content items in a JSON format and use your preferred technology to present them in different channels.
The feature preserves a friendly editing experience in Umbraco while ensuring a performant delivery of content in a headless fashion. With the different extension points, you can tailor the API to fit a broad range of requirements.
The Delivery API is an opt-in feature in Umbraco. It must be explicitly enabled through configuration before it can be utilized.
When creating your project, you can enable the Delivery API using the --use-delivery-api
or -da
flag. This will automatically add the necessary configuration to your project.
You can also enable the Delivery API at a later point by following these steps:
Open your project's appsettings.json
.
Insert the DeliveryApi
configuration section under Umbraco:CMS
.
Add the Enabled
key and set its value to true
.
Open Program.Cs
Add .AddDeliveryApi()
to builder.CreateUmbracoBuilder()
Once the Content Delivery API is enabled, the next step is to rebuild the Delivery API content index (DeliveryApiContentIndex). This can be done using the Examine Management dashboard in the Settings section of the Umbraco Backoffice.
Access the Umbraco Backoffice.
Navigate to the Settings section.
Open the Examine Management dashboard.
Scroll down to find the Tools.
Use the Rebuild index button.
Once the index is rebuilt, the API can serve the latest content from the multiple-items endpoint.
When the Delivery API is enabled in your project, all your published content will be made available to the public by default.
A few additional configuration options will allow you to restrict access to the Delivery API endpoints and limit the content returned.
Find a description of each of the configuration keys in the table below.
Are you using Umbraco Cloud?
When hosting your Umbraco website on Umbraco Cloud, security should always be prioritized for sensitive information like API keys. Rather than storing it as plain text in the appsettings.json
file use the Umbraco Cloud's built-in secrets management. This feature lets you store and manage sensitive data, keeping your API key safe from potential exposure or unauthorized access. To learn more about implementing secrets management, read the Secrets management documentation.
To test the functionality of the API, you need to create some content first.
Before exploring the API endpoints detailed below, there are a few concepts to know.
The Delivery API output can represent a specific content item or a paged list of multiple items.
When referring to a specific content item in your API requests, the id
parameter always refers to the item’s key (GUID).
GET
/umbraco/delivery/api/v2/content/item/{id}
Returns a single item.
GET
/umbraco/delivery/api/v2/content/item/{path}
Returns a single item.
GET
/umbraco/delivery/api/v2/content/items
Returns single or multiple items by id.
GET
/umbraco/delivery/api/v2/content
Returns single or multiple items.
All endpoints are documented in a Swagger document at {yourdomain}/umbraco/swagger
. This document is not available in production mode by default. For more information read the API versioning and OpenAPI article.
The Content Delivery API provides query parameters that allow you to customize the content returned by the API. The relevant query parameters for each endpoint are already specified in the corresponding documentation above.
In addition to standard parameters like skip
and take
, the API provides different possibilities for the value of the expand
, fields
, fetch
, filter
and sort
parameters. Below are the options that are supported out of the box.
You can extend the built-in selector, filter, and sorting capabilities of the Delivery API by creating custom query handlers.
Refer to the Property expansion and limiting concept for more information about this parameter.
?expand=properties[$all]
All expandable properties on the retrieved content item will be expanded.
?expand=properties[alias1]
A specific expandable property with the property alias alias1
will be expanded.
?expand=properties[alias1,alias2,alias3]
Multiple expandable properties with the specified property aliases will be expanded.
?expand=properties[alias1[properties[nestedAlias1,nestedAlias2]]]
The property with the property alias alias1
will be expanded, and likewise the properties nestedAlias1
and nestedAlias2
of the expanded alias1
property.
Refer to the Property expansion and limiting concept for more information about this parameter.
?fields=properties[$all]
Includes all properties of the retrieved content item in the output.
?fields=properties[alias1]
Includes only the property with the property alias alias1
in the output.
?fields=properties[alias1,alias2,alias3]
Includes only the properties with the specified property aliases in the output.
?fields=properties[alias1[properties[nestedAlias1,nestedAlias2]]]
Includes only the property with the property alias alias1
in the output. If this property is expanded, only the properties nestedAlias1
and nestedAlias2
of the expanded alias1
property are included.
You can apply a selector option to the /umbraco/delivery/api/v2/content
endpoint to query content items based on their structure. The selector allows you to fetch different subsets of items based on a GUID or path of a specific content item. The Delivery API will search all available content items if no fetch
parameter is provided. The following built-in selectors can be used out of the box:
?fetch=ancestors:id/path
All ancestors of a content item specified by either its id
or path
will be retrieved.
?fetch=children:id/path
All immediate children of a content item specified by either its id
or path
will be retrieved.
?fetch=descendants:id/path
All descendants of a content item specified by either its id
or path
will be retrieved.
Only one selector option can be applied to a query at a time. You cannot combine multiple fetch parameters in a single query.
For example, the following API call will attempt to retrieve all the content items that are directly below an item with the id dc1f43da-49c6-4d87-b104-a5864eca8152
:
Request
The filter query parameter allows you to specify one or more filters. These filters must match for a content item to be included in the response. The API provides a few built-in filters that you can use right away with the /umbraco/delivery/api/v2/content
endpoint:
?filter=contentType:alias
This filter restricts the results to content items that belong to the specified content type. Replace alias
with the alias of the content type you want to filter by.
?filter=name:nodeName
Only content items whose name matches the specified value will be returned when this filter is applied. Replace nodeName
with the name of the item that you want to filter by.
The contentType
and name
filters support negation. You can exclude content items from the result set that match the filter criteria using an exclamation mark before the filter value.
For example, you can fetch all content items that are not of type article
like this: ?filter=contentType:!article
.
?filter=createDate>date
Only content items created later than the specified value will be returned when this filter is applied. Replace date
with the date that you want to filter by.
?filter=updateDate>date
Only content items updated later than the specified value will be returned when this filter is applied. Replace date
with the date that you want to filter by.
The createDate
and updateDate
filters support both "greater than", "greater than or equal", "less than" and "less than or equal":
Use > for "greater than" filtering.
Use >: for "greater than or equal" filtering.
Use < for "less than" filtering.
Use <: for "less than or equal" filtering.
Multiple filters can be applied to the same request in addition to other query parameters:
Request
This technique can also be used to perform range filtering. For example, fetch articles created in 2023:
Request
Specifying how the results should be ordered, can be achieved using the sort
query option. You can use this parameter to sort the content items by fields, including create date
, level
, name
, sort order
, and update date
. For each field, you can specify whether the items should be sorted in ascending (asc) or descending (desc) order. Without a sort
query parameter, the order of the results will be determined by the relevance score of the DeliveryApiContentIndex for the search term.
?sort=createDate:asc/desc
An option to sort the results based on the creation date of the content item in either asc
or desc
order.
?sort=level:asc/desc
An option to sort the results based on the level of the content item in the content tree in either asc
or desc
order.
?sort=name:asc/desc
An option to sort the results based on the name of the content item in either asc
or desc
order.
?sort=sortOrder:asc/desc
An option to sort the results based on the sort order of the content item in either asc
or desc
order.
?sort=updateDate:asc/desc
An option to sort the results based on the last update date of the content item in either asc
or desc
order.
Different sorting options can be combined for the /umbraco/delivery/api/v2/content
endpoint, allowing for more advanced sorting functionality. Here is an example:
Request
The Delivery API has been designed for extensibility, offering multiple extension points that provide greater flexibility and customization options. These extension points allow you to tailor the API's behavior and expand its capabilities to meet your specific requirements.
You can find detailed information about the specific areas of extension in the articles below:
.NET imposes a limit on the depth of object nesting within rendered JSON. This is done to detect cyclic references. Learn more about it in the official .NET API docs.
If the limit is exceeded, .NET will throw a JsonException
.
The content models might be so deeply nested that the Delivery API produces JSON that exceeds this limit. If this happens, the JsonException
will be logged and shown in the Umbraco log viewer.
To handle this we have to change the limit. Since the Delivery API has its own JSON configuration, we can do so without affecting the rest of our site.
Add the following using
statements to Program.cs
:
Add the following code snippet to the Program.cs
file:
The Content Delivery API provides a powerful and flexible way to retrieve content from the Umbraco CMS. There are, however, certain limitations to be aware of.
In this section, we will discuss some of the known limitations of the API, and how to work around them if necessary.
The Delivery API supports protected content and member authentication. This is an opt-in feature. You can read more about it in the Protected Content in the Delivery API article.
If member authentication is not explicitly enabled, protected content is ignored and never exposed by the Delivery API.
As a result, lifting protection from a content item requires an additional step to ensure it becomes accessible through the Delivery API. The recommended way is to publish the content item again. Alternatively, you can manually rebuild the DeliveryApiContentIndex
to reflect the changes.
Certain limitations are associated with some of the built-in property editors in Umbraco. These limitations are listed below.
Internal links may be insufficient in a multi-site setup when outputting the Rich Text Editor content as HTML (the default format). There is a possibility that this limitation may be addressed in future updates. However, consider the alternative approach to rendering the Rich Text Editor content as JSON.
The Member Picker property editor is not supported in the Delivery API to avoid the risk of leaking member data.
The Content Picker property editor is not supported in the Delivery API when configured for Members. This is due to the concern of potentially leaking member data.
DisallowedContentTypeAliases
When changing the content type aliases in the Umbraco:CMS:DeliveryApi:DisallowedContentTypeAliases
configuration setting, DeliveryApiContentIndex
should be rebuilt. This ensures that disallowed content types are not exposed through the Delivery API.
Alternatively, the relevant content items can be republished. This will ensure that changes are reflected, eliminating the need to rebuild the index.
Configure custom preview URLs to provide editors with seamless access to external preview environments for the Content Delivery API data.
With Umbraco, you can save and preview draft content before going live. The preview feature allows you to visualize how a page will look once it is published, directly from within the backoffice. This is also possible for the Content Delivery API data. You can extend the preview functionality in the backoffice by configuring external preview URLs for client libraries consuming the Content Delivery API.
To get familiar with the preview functionality in the Delivery API, please refer to the section.
The support for configuring additional preview environments in the Delivery API was introduced in version 12.3.
If your client libraries feature preview functionality, you can enable editors in Umbraco to navigate directly to their preferred preview environments. To achieve this, start by generating the necessary URLs for each environment you wish to allow for preview. These URLs need to trigger preview mode within your application, which will fetch and present draft content from the Delivery API.
Once you have these preview URLs, you will need to register them through code in Umbraco.
Additionally, there are plans to simplify this process further. In an upcoming major version of Umbraco, a UI will be introduced, allowing you to configure these custom preview URLs directly from the backoffice.
Here is an example of how to register such preview URLs for both variant and invariant content using a notification handler:
The purpose of this notification handler is to dynamically generate additional preview URLs for published content items only (for the sake of simplicity). It constructs two custom preview URLs, one for a development environment and another for a staging environment. These URLs include the content's route, culture variant, and a preview
query parameter to enable preview mode in the client application.
You can then register your notification handler in a composer like this:
Now that we have set up additional preview URLs for the Delivery API data, you can access them from the Content section. When you open a content node, you will see new preview options for the external environments you have configured. Next to the regular "Save and preview" button, there is an arrow for the multiple URLs that have been added. Click it to see all the available preview URLs, as shown below:
Below is an example with variants, showcasing both the English and Danish versions of a content node.
Using the Media Delivery API.
The Media Delivery API allows for accessing the Umbraco media items in a headless manner. This API applies many of the same concepts as its content counterpart, although with fewer options. If you haven't already, please familiarize yourself with the before reading this article.
The Media Delivery API specification is created to mimic that of the Content Delivery API. However, the default implementation of this specification is limited and does not support the entire specification.
Unlike the Content Delivery API, the Media Delivery API does not feature an extension model for querying.
The reasoning behind is that third-party media systems might support a complete implementation of the specification. If the demand rises, the default implementation might eventually cover the entire specification.
To use the Media Delivery API you must first enable it. Even if the Content Delivery API is enabled, the Media Delivery API remains disabled by default.
The Media Delivery API is enabled by adding the Media
section to the DeliveryApi
configuration in appsettings.json
:
As this configuration sample illustrates, it is possible to restrict public access to media independently from content. As with the Content Delivery API, media is publicly accessible by default when the Media Delivery API is enabled.
The Media
configuration can only become more restrictive than the DeliveryApi
configuration:
If DeliveryApi:Enabled
is false
, the DeliveryApi:Media:Enabled
configuration option has no effect. The Media Delivery API cannot be enabled on its own.
If DeliveryApi:PublicAccess
is false
, the DeliveryApi:Media:PublicAccess
configuration option has no effect. The Media Delivery API cannot be publicly available if the Content Delivery API is not.
The Media Delivery API can either be queried for a specific media item or a paged list of multiple items.
In the Media Delivery API, id
parameters always refer to media item keys (Guid
), not node ids (integer
).
GET
/umbraco/delivery/api/v2/media/item/{id}
Returns a single item.
GET
/umbraco/delivery/api/v2/media/item/{path}
Returns a single item.
GET
/umbraco/delivery/api/v2/media/items
Returns single or multiple items by id.
GET
/umbraco/delivery/api/v2/media
Returns single or multiple items.
Fetch a media item by its ID:
Fetch a media item inside a folder structure by its full path, and expand its author
property:
Fetch two media items by their ids:
Fetch the first 10 media items of type Image
at root level. Return the found items sorted by name ascending:
Fetch the first 5 media items inside a folder structure. Return only items of type Image
whose item names contain "size".
The Media Delivery API outputs the JSON structure outlined below to represent media items:
Item path
, createDate
, updateDate
, id
, name
, and mediaType
are always included in the response.
url
, extension
and the size in bytes
are included for all files (not for folders).
width
and height
(in pixels) are included for most images.
Depending on Umbraco Data Type configuration, focalPoint
and crops
are included for most images.
Additional editorial properties from the media type can be found in the properties
collection.
Discover how to customize the Content Delivery API's response for your custom property editors.
Out of the box, the Delivery API supports custom property editors, ensuring they are rendered alongside the built-in ones in Umbraco. However, if the output generated by your property editor isn't optimal for a headless context, you have the ability to customize the API response. This customization won't impact the Razor rendering, allowing you to tailor the Content Delivery API response according to your specific requirements.
In this article, we'll look into how you can work with the IDeliveryApiPropertyValueConverter
interface and implement custom for your custom property editors.
The examples in this article revolve around the fictional My.Custom.Picker
property editor. This property editor stores the key of a single content item and is backed by a property value converter.
We will not dive into the details of creating a custom property editor for Umbraco in this article. If you need guidance on that, please refer to the and articles.
To customize the output of a property value editor in the Delivery API, we need to opt-in by implementing the IDeliveryApiPropertyValueConverter
interface.
The code example below showcases the implementation of this interface in the property value converter for My.Custom.Picker
. Our focus will be on the methods provided by the IDeliveryApiPropertyValueConverter
, as they are responsible for customizing the Delivery API response.
Towards the end of the example, you will find the response models that we will be using.
The IsConverter()
and GetPropertyValueType()
methods are inherited from the PropertyValueConverterBase
class, which is covered in the article.
The Implementation of the IDeliveryApiPropertyValueConverter
interface can be found in the following methods:
GetDeliveryApiPropertyCacheLevel()
: This method specifies the cache level used for our property representation in the Delivery API response.
GetDeliveryApiPropertyValueType()
: This method defines the value type of the custom property output for the Delivery API response.
ConvertIntermediateToDeliveryApiObject()
: This method converts the value from the property editor to the desired custom object in a headless context.
In the given example, the content key (Guid
value) is used when rendering with Razor. This is sufficient because Razor provides full access to the published content within the rendering context. In a headless context, we do not have the same access. To prevent subsequent round-trips to the server, we create a richer output model specifically for the Delivery API.
The following example request shows how our custom implementation is reflected in the resulting API response. In this case, our custom property editor is configured under the alias "pickedItem"
.
Request
Response
Property expansion allows us to conditionally add another level of detail to the Delivery API output. Usually, these additional details are "expensive" to retrieve (for example, requiring database access to populate). By applying property expansion, we provide the option for the caller of the API to opt-in explicitly to this "expensive" operation. From the caller's perspective, the alternative might be an even more expensive additional round-trip to the server.
In our example, property expansion is implemented within ConvertIntermediateToDeliveryApiObject()
. By considering the value of the expanding
parameter, we can modify the BuildDeliveryApiCustomPicker()
method as follows:
If the expanding
parameter is false
, the method returns the same shallow representation of the referenced content item as before. Otherwise, we retrieve the corresponding IPublishedContent
and construct our response object accordingly.
To see the expanded output in the API response, we need to add the expand
query parameter to our request. We can use either ?expand=properties[$all]
to expand all properties or ?expand=properties[pickedItem]
to expand the specific 'pickedItem'
property.
Request
Response
The itemDetails
property of the pickedItem
in the JSON response contains the additional details of the selected content item.
Configuration key | Description |
---|---|
Name | Type | Description |
---|---|---|
Name | Type | Description |
---|---|---|
Name | Type | Description |
---|---|---|
Response Status | Description |
---|---|
Name | Type | Description |
---|---|---|
Name | Type | Description |
---|---|---|
Name | Type | Description |
---|---|---|
Response Status | Description |
---|---|
Name | Type | Description |
---|---|---|
Name | Type | Description |
---|---|---|
Response Status | Description |
---|---|
Name | Type | Description |
---|---|---|
Name | Type | Description |
---|---|---|
Response Status | Description |
---|---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
Name | Type | Description |
---|
GetDeliveryApiPropertyCacheLevelForExpansion()
: This method specifies the cache level used for our property representation in the Delivery API response when is applied.
PublicAccess
Determines whether the enabled Delivery API should be publicly accessible or if access should require an API key.
ApiKey
Specifies the API key needed to authorize access to the API when public access is disabled. This setting is also used to access draft content for preview.
DisallowedContentTypeAliases
Contains the aliases of the content types that should never be exposed through the Delivery API, regardless of any other configurations.
RichTextOutputAsJson
Enable outputting rich text content as JSON rather than the default HTML output. JSON can be a preferred format in many scenarios, not least because it supports the routing of internal links better than HTML does.
id*
String
GUID of the content item.
expand
String
Which properties to expand and therefore include in the output if they refer to another piece of content.
fields
String
Which properties to include in the response. All properties are included by default.
Accept-Language
String
Requested culture.
Api-Key
String
Access token.
Preview
Boolean
Whether draft content is requested.
Start-Item
String
URL segment or GUID of the root content item.
200: OK
Content item.
401: Unauthorized
Missing permissions after protection is set up.
404: Not Found
Content item not found.
path*
String
Path of the content item.
expand
String
Which properties to expand and therefore include in the output if they refer to another piece of content.
fields
String
Which properties to include in the response. All properties are included by default.
Accept-Language
String
Requested culture.
Api-Key
String
Access token.
Preview
Boolean
Whether draft content is requested.
Start-Item
String
URL segment or GUID of the root content item.
200: OK
Content item.
401: Unauthorized
Missing permissions after protection is set up.
404: Not Found
Content item not found.
id*
String Array
GUIDs of the content items.
expand
String
Which properties to expand in the response.
fields
String
Which properties to include in the response. All properties are included by default.
Accept-Language
String
Requested culture.
Api-Key
String
Access token.
Preview
Boolean
Whether draft content is requested.
Start-Item
String
URL segment or GUID of the root content item.
200: OK
Content item.
401: Unauthorized
Missing permissions after protection is set up.
fetch
String
Structural query string option (e.g. ancestors
, children
, descendants
).
filter
String Array
Filtering query string options (e.g. contentType
, name
, createDate
, updateDate
).
sort
String Array
Sorting query string options (e.g. createDate
, level
, name
, sortOrder
, updateDate
).
skip
Integer
Amount of items to skip.
take
Integer
Amount of items to take.
expand
String
Which properties to expand and therefore include in the output if they refer to another piece of content.
fields
String
Which properties to include in the response. All properties are included by default.
Accept-Language
String
Requested culture.
Api-Key
String
Access token.
Preview
Boolean
Whether draft content is requested.
Start-Item
String
URL segment or GUID of the root content item.
200: OK
Content item.
401: Unauthorized
Missing permissions after protection is set up.
404: Not Found
Content item not found.
id* | String | GUID of the media item |
expand | String | Which properties to expand in the response |
fields | String | Which properties to include in the response (by default all properties are included) |
Api-Key | String | Access token |
path* | String | Path of the media item. The path is composed by the names of any ancestor folders and the name of the media item itself, separated by
. |
expand | String | Which properties to expand in the response |
fields | String | Which properties to include in the response (by default all properties are included) |
Api-Key | String | Access token |
id* | String Array | GUIDs of the media items |
expand | String | Which properties to expand in the response |
fields | String | Which properties to include in the response (by default all properties are included) |
Api-Key | String | Access token |
fetch* | String | Structural query string option (e.g. Please note: The default API implementation only supports |
filter | String Array | Filtering query string options (e.g. |
sort | String Array | Sorting query string options (e.g. |
skip | Integer | Amount of items to skip |
take | Integer | Amount of items to take |
expand | String | Which properties to expand in the response |
fields | String | Which properties to include in the response (by default all properties are included) |
Api-Key | String | Access token |
The following example uses IPublishedSnapshotAccessor
, which is obsolete in Umbraco 15 and will be removed in a future version. For more information, see the article.
The following example uses IPublishedSnapshotAccessor
, which is obsolete in Umbraco 15 and will be removed in a future version. For more information, see the article.
The following example uses Umbraco.Cms.Core.PublishedCache
, IPublishedSnapshotAccessor
, and PropertyCacheLevel.Snapshot
, which are obsolete in Umbraco 15 and will be removed in a future version. For more information, see the Version specific upgrades article.