Umbraco CMS
CloudHeartcoreDXPMarketplace
14.latest
14.latest
  • Umbraco CMS Documentation
  • Legacy Documentation
    • Our Umbraco
    • GitHub
  • Release Notes
  • Contribute
  • Sustainability Best Practices
  • Fundamentals
    • Get to know Umbraco
    • Setup
      • Requirements
      • Installation
        • Install using .NET CLI
        • Running Umbraco in Docker using Docker Compose
        • Install using Visual Studio
        • Local IIS With Umbraco
        • Install using Visual Studio Code
        • Installing Nightly Builds
        • Running Umbraco on Linux/macOS
        • Unattended Installs
      • Upgrade your project
        • Version Specific Upgrades
          • Upgrade from Umbraco 8 to the latest version
          • Migrate content to Umbraco 8
          • Minor upgrades for Umbraco 8
          • Upgrade to Umbraco 7
          • Minor upgrades for Umbraco 7
      • Server setup
        • Running Umbraco On Azure Web Apps
        • Hosting Umbraco in IIS
        • File And Folder Permissions
        • Runtime Modes
        • Umbraco in Load Balanced Environments
          • Load Balancing Azure Web Apps
          • Standalone File System
          • Advanced Techniques With Flexible Load Balancing
          • Logging With Load Balancing
    • Backoffice
      • Sections
      • Property Editors
        • Built-in Property Editors
          • Checkbox List
          • Collection
          • Color Picker
          • Content Picker
          • Document Picker
          • DateTime
          • Date
          • Decimal
          • Email Address
          • Eye Dropper Color Picker
          • File Upload
          • Image Cropper
          • Label
          • Markdown Editor
          • Media Picker
          • Member Group Picker
          • Member Picker
          • Multi Url Picker
          • Repeatable Textstrings
          • Numeric
          • Radiobutton List
          • Slider
          • Tags
          • Textarea
          • Textbox
          • Toggle
          • User Picker
          • Block Editors
            • Block Grid
            • Block List
          • Dropdown
          • Rich Text Editor
            • Rich Text Editor Configuration
            • Rich Text Editor Styles
            • Rich Text Editor Plugins
            • Blocks in Rich Text Editor
      • Login
      • Document Blueprints
      • Sidebar
      • Log Viewer
      • Language Variants
      • Settings Dashboards
    • Data
      • Defining Content
        • Default Document Types
        • Document Type Localization
      • Creating Media
        • Default Data/Media Types
      • Members
      • Data Types
        • Default Data Types
      • Scheduled Publishing
      • Using Tabs
      • Users
      • Relations
      • Dictionary Items
      • Content Version Cleanup
    • Design
      • Templates
        • Basic Razor Syntax
        • Razor Cheatsheet
      • Rendering Content
      • Rendering Media
      • Partial Views
      • Stylesheets And JavaScript
    • Code
      • Service APIs
      • Subscribing To Notifications
      • Creating Forms
      • Debugging
        • Logging
      • Source Control
  • Implementation
    • Learn how Umbraco works
    • Routing
      • Controller & Action Selection
      • Execute Request
      • Request Pipeline
    • Custom Routing
      • Adding a hub with SignalR and Umbraco
    • Controllers
    • Data Persistence (CRUD)
    • Composing
    • Integration Testing
    • Nullable Reference Types
    • Services and Helpers
      • Circular Dependencies
    • Unit Testing
  • Customizing
    • Extend and customize the editing experience
    • Project Bellissima
    • Setup Your Development Environment
      • Vite Package Setup
    • Foundation
      • Working with Data
        • Repositories
        • Context API
        • Store
        • States
      • Contexts
        • Property Dataset Context
      • Umbraco Element
        • Controllers
          • Write your own controller
      • Sorting
      • Routes
      • Icons
      • Backoffice Localization
      • Terminology
    • Extension Overview
      • Extension Registry
        • Extension Registration
        • Extension Manifest
      • Extension Types
        • Menu
        • Header Apps
        • Icons
        • Modals
          • Confirm Dialog
          • Custom Modals
          • Route Registration
        • Bundle
        • Kind
        • Backoffice Entry Point
        • Extension Conditions
        • Dashboards
        • Entity Actions
        • Entity Bulk Actions
        • Entity Create Option Action
        • Trees
        • Global Context
        • Section Sidebar
        • Section View
        • Sections
        • Workspace Context
        • Workspace Views
        • Workspace Actions
        • Localization
      • Extension Kind
      • Extension Conditions
      • Custom Extension types
    • Sections & Trees
    • Searchable Trees (ISearchableTree)
    • Property Editors
      • Property Editors Composition
        • Property Editor Schema
        • Property Editor UI
      • Property Value Converters
      • Property Actions
      • Integrate Property Editors
      • Tracking References
      • Content Picker Value Converter Example
      • Property Dataset
      • Integrate Validaction
    • Workspaces
    • Umbraco Package
    • UI Library
  • Extending
    • Build on Umbraco functionality
    • Health Check
      • Health Check Guides
        • Click-Jacking Protection
        • Content Content Security Policy (CSP)
        • Content/MIME Sniffing Protection
        • Cross-site scripting Protection (X-XSS-Protection header)
        • Debug Compilation Mode
        • Excessive Headers
        • Fixed Application Url
        • Folder & File Permissions
        • HTTPS Configuration
        • Notification Email Settings
        • SMTP
        • Strict-Transport-Security Header
    • Language Files & Localization
      • .NET Localization
    • Backoffice Search
    • Creating a Custom Database Table
    • Embedded Media Providers
    • Custom File Systems (IFileSystem)
      • Using Azure Blob Storage for Media and ImageSharp Cache
    • Configuring Azure Key Vault
    • Packages
      • Creating a Package
      • Language file for packages
      • Listing a Package on the Umbraco Marketplace
      • Good practice and defaults
      • Packages on Umbraco Cloud
      • Installing and Uninstalling Packages
      • Maintaining packages
      • Create accessible Umbraco packages
      • Example Package Repository
  • Reference
    • Dive into the code
    • Configuration
      • Basic Authentication Settings
      • Connection strings settings
      • Content Dashboard Settings
      • Content Settings
      • Data Types Settings
      • Debug settings
      • Examine settings
      • Exception filter settings
      • FileSystemProviders Configuration
      • Global Settings
      • Health checks
      • Hosting settings
      • Imaging settings
      • Indexing settings
      • Install Default Data Settings
      • Logging settings
      • Maximum Upload Size Settings
      • Models builder settings
      • NuCache Settings
      • Package Migration
      • Plugins settings
      • Request handler settings
      • Runtime settings
      • Security Settings
      • Serilog settings
      • Type finder settings
      • Unattended
      • Web routing
    • Templating
      • Models Builder
        • Introduction
        • Configuration
        • Builder Modes
        • Understand and Extend
        • Using Interfaces
        • Tips and Tricks
      • Working with MVC
        • Working with MVC Views in Umbraco
        • View/Razor Examples
        • Using MVC Partial Views in Umbraco
        • Using View Components in Umbraco
        • Querying & Traversal
        • Creating Forms
      • Macros
    • Querying & Models
      • IMemberManager
      • IPublishedContentQuery
      • ITagQuery
      • UDI Identifiers
      • UmbracoContext helper
      • UmbracoHelper
      • IPublishedContent
        • IPublishedContent Collections
        • IPublishedContent IsHelpers
        • IPublishedContent Property Access & Extension Methods
    • Routing & Controllers
      • Custom MVC controllers (Umbraco Route Hijacking)
      • Custom MVC Routes
      • Custom Middleware
      • URL Rewrites in Umbraco
      • Special Property Type aliases for routing
      • URL Redirect Management
      • Routing in Umbraco
        • FindPublishedContentAndTemplate()
        • IContentFinder
        • Inbound request pipeline
        • Outbound request pipeline
        • Published Content Request Preparation
      • Surface controllers
        • Surface controller actions
      • Umbraco API Controllers
        • Porting old Umbraco API Controllers
    • Content Delivery API
      • Custom property editors support
      • Extension API for querying
      • Media Delivery API
      • Protected content in the Delivery API
      • Output caching
      • Property expansion and limiting
      • Additional preview environments support
    • Webhooks
      • Expanding Webhook Events
    • API versioning and OpenAPI
    • Searching
      • Examine
        • Examine Management
        • Examine Manager
        • Custom indexing
        • PDF indexes and multisearchers
        • Quick-start
    • Using Notifications
      • Notification Handler
      • CacheRefresher Notifications Example
      • ContentService Notifications Example
      • Creating And Publishing Notifications
      • Determining if an entity is new
      • MediaService Notifications Example
      • MemberService Notifications Example
      • Sending Allowed Children Notification
      • Umbraco Application Lifetime Notifications
      • EditorModel Notifications
        • Customizing the "Links" box
      • Hot vs. cold restarts
    • Inversion of Control / Dependency injection
    • Management
      • Using Umbraco services
        • Consent Service
        • Media Service
        • Relation Service
        • Content Service
        • Content Type Service
        • Localization Service
        • User Service
    • Plugins
      • Creating Resolvers
      • Finding types
    • Cache & Distributed Cache
      • Accessing the cache
      • ICacheRefresher
      • IServerMessenger
      • Getting/Adding/Updating/Inserting Into Cache
      • Examples
        • Working with caching
    • Response Caching
    • Security
      • API rate limiting
      • BackOfficeUserManager and Events
      • Cookies
      • Replacing the basic username/password check
      • External login providers
      • Locking of Users and password reset
      • Reset admin password
      • Umbraco Security Hardening
      • Umbraco Security Settings
      • Sensitive data
      • Sanitizing the Rich Text Editor
      • Setup Umbraco for a FIPS Compliant Server
      • HTTPS
      • Two-factor Authentication
      • Server-side file validation
    • Scheduling
    • Common Pitfalls & Anti-Patterns
    • API Documentation
    • Debugging with SourceLink
    • Language Variation
    • UmbracoMapper
    • Distributed Locks
    • Management API
      • Setup OAuth using Postman
    • Custom Swagger API
    • Umbraco Flavored Markdown
  • Tutorials
    • Overview
    • Creating a Basic Website
      • Getting Started
      • Document Types
      • Creating Your First Template
      • CSS and Images
      • Displaying the Document Type Properties
      • Creating a Master Template
      • Creating Pages and Using the Master Template
      • Setting the Navigation Menu
      • Articles and Article Items
      • Adding Language Variants
      • Conclusions
    • Creating your First Extension
    • Creating a Custom Dashboard
      • Adding localization to the dashboard
      • Adding functionality to the Dashboard
      • Using Umbraco UI library in the Dashboard
    • Creating a Property Editor
      • Adding configuration to a Property Editor
      • Integrating context with a Property Editor
      • Custom value conversion for rendering
      • Adding server-side validation
        • Default Property Editor Schema aliases
    • Creating a Multilingual Site
    • Add Google Authentication (Users)
    • Add Microsoft Entra ID authentication (Members)
    • Creating Custom Database Tables with Entity Framework
    • The Starter Kit
      • Lessons
        • Customize the Starter Kit
        • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
        • Add Open Graph
          • Add Open Graph - Step 1
          • Add Open Graph - Step 2
          • Add Open Graph - Step 3
          • Add Open Graph - Step 4
          • Add Open Graph - Summary
        • Ask For Help and Join the Community
    • Editor's Manual
      • Getting Started
        • Logging In and Out
        • Umbraco Interface
        • Creating, Saving and Publishing Content Options
        • Finding Content
        • Editing Existing Content
        • Sorting Pages
        • Moving a Page
        • Copying a Page
        • Deleting and Restoring Pages
      • Working with Rich Text Editor
      • Version Management
        • Comparing Versions
        • Rollback to a Previous Version
      • Media Management
        • Working with Folders
        • Working with Media Types
        • Cropping Images
      • Tips & Tricks
        • Refreshing the Tree View
        • Audit Trail
        • Notifications
        • Preview Pane Responsive View
        • Session Timeout
    • Multisite Setup
    • Member Registration and Login
    • Custom Views for Block List
    • Connecting Umbraco Forms and Zapier
    • Creating an XML Sitemap
    • Implement Custom Error Pages
    • Create a custom maintenance page
    • Creating a backoffice API
      • Documenting your controllers
      • Adding a custom Swagger document
      • Versioning your API
      • Polymorphic output in the Management API
      • Umbraco schema and operation IDs
      • Access policies
Powered by GitBook
On this page
  • API versioning
  • Swagger route and/or availability
  • Adding custom operation IDs
  • Adding custom schema IDs
  • Adding your own Swagger documents
Edit on GitHub
Export as PDF
  1. Reference

API versioning and OpenAPI

How to use API versioning and OpenAPI (Swagger) for your own APIs.

PreviousExpanding Webhook EventsNextSearching

Last updated 11 months ago

Umbraco ships with Swagger to document the Content Delivery API. Swagger and the Swagger UI is available at {yourdomain}/umbraco/swagger. For security reasons, both are disabled in production environments.

Due to the way OpenAPI works within ASP.NET Core, we have to apply some configurations in a global scope. If your Umbraco site used Swagger previous to Umbraco 12, these global configurations may interfere with your setup.

In this article we'll explore concrete solutions to overcome challenges with the global configurations.

Umbraco uses to handle Swagger and the Swagger UI.

If you have been using previous to Umbraco 12, chances are your Swagger setup will continue to work in Umbraco 12+ without any changes. Swashbuckle.AspNetCore and NSwag can coexist within the same site, as long as there are no conflicting routes between the two.

That being said, it would be sensible to consider migrating your API documentation to Swashbuckle.AspNetCore. This way you can avoid having multiple dependencies that perform the same tasks.

API versioning

The Umbraco APIs rely on having the requested API version as part of the URL. If you prefer a different versioning for your own APIs, you can setup alternatives while still preserving the functionality of the Umbraco API.

The following code sample illustrates how you can use a custom header to pass the requested API version to your own APIs.

MyConfigureApiVersioningOptions.cs
using Asp.Versioning;
using Microsoft.Extensions.Options;

namespace My.Custom.Swagger;

public class MyConfigureApiVersioningOptions : IConfigureOptions<ApiVersioningOptions>
{
    public void Configure(ApiVersioningOptions options)
        => options.ApiVersionReader = ApiVersionReader.Combine(
            // the URL segment version reader is required for the Umbraco APIs
            new UrlSegmentApiVersionReader(),
            // here you can add additional version readers to suit your needs
            new HeaderApiVersionReader("my-api-version"));
}

public static class MyConfigureApiVersioningUmbracoBuilderExtensions
{
    // call this from Program.cs, i.e.:
    //     builder.CreateUmbracoBuilder()
    //         ...
    //         .ConfigureMyApiVersioning()
    //         .Build();
    public static IUmbracoBuilder ConfigureMyApiVersioning(this IUmbracoBuilder builder)
    {
        builder.Services.ConfigureOptions<MyConfigureApiVersioningOptions>();
        return builder;
    }
}

Swagger route and/or availability

As mentioned in the beginning of this article, Umbraco exposes Swagger and the Swagger UI at {yourdomain}/umbraco/swagger. Both are disabled when the site is in production mode.

The code sample below shows how to change the Swagger route and availability.

MySwaggerRouteTemplatePipelineFilter.cs
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Cms.Web.Common.ApplicationBuilder;

namespace My.Custom.Swagger;

public class MySwaggerRouteTemplatePipelineFilter : SwaggerRouteTemplatePipelineFilter
{
    public MySwaggerRouteTemplatePipelineFilter(string name) : base(name)
    {
    }

    /// <summary>
    /// This is how you change the route template for the Swagger docs.
    /// </summary>
    protected override string SwaggerRouteTemplate(IApplicationBuilder applicationBuilder) => "swagger/{documentName}/swagger.json";

    /// <summary>
    /// This is how you change the route for the Swagger UI.
    /// </summary>
    protected override string SwaggerUiRoutePrefix(IApplicationBuilder applicationBuilder) => "swagger";

    /// <summary>
    /// This is how you configure Swagger to be available always.
    /// Please note that this is NOT recommended.
    /// </summary>
    protected override bool SwaggerIsEnabled(IApplicationBuilder applicationBuilder) => true;
}

public static class MyConfigureSwaggerRouteUmbracoBuilderExtensions
{
    // call this from Program.cs, i.e.:
    //     CreateUmbracoBuilder()
    //         ...
    //         .ConfigureMySwaggerRoute()
    //         .Build();
    public static IUmbracoBuilder ConfigureMySwaggerRoute(this IUmbracoBuilder builder)
    {
        builder.Services.Configure<UmbracoPipelineOptions>(options =>
        {
            // include this line if you do NOT want the Swagger docs at /umbraco/swagger
            options.PipelineFilters.RemoveAll(filter => filter is SwaggerRouteTemplatePipelineFilter);

            // setup your own Swagger routes
            options.AddFilter(new MySwaggerRouteTemplatePipelineFilter("MyApi"));
        });
        return builder;
    }
}

Adding custom operation IDs

Custom operation IDs can be a great way to make your API easier to use. Especially for consumers that generate API contracts from your Swagger documents.

The Umbraco APIs use custom operation IDs for that exact reason. In order to remain as un-intrusive as possible, these custom operation IDs are not applied to your APIs.

If you want to apply custom operation IDs to your APIs, you must ensure that the Umbraco APIs retain their custom operation IDs. The following code sample illustrates how this can be done.

MyOperationIdSelector.cs
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Umbraco.Cms.Api.Common.OpenApi;

namespace My.Custom.Swagger;

public class MyOperationIdSelector : OperationIdSelector
{
    public override string? OperationId(ApiDescription apiDescription, ApiVersioningOptions apiVersioningOptions)
    {
        // use this if you want to opt into the default Umbraco operation IDs:
        // return UmbracoOperationId(apiDescription, apiVersioningOptions);

        // only handle your own APIs here - make sure to let the base class handle the Umbraco APIs
        if (apiDescription.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor
            || controllerActionDescriptor.ControllerTypeInfo.Namespace?.StartsWith("My.Custom.Api") is false)
        {
            return base.OperationId(apiDescription, apiVersioningOptions);
        }

        // build your own logic to generate operation IDs here
        return apiDescription.RelativePath is null
            ? null
            : string.Join(string.Empty, apiDescription.RelativePath.Split(new[] { '/', '-' }).Select(segment => segment.ToFirstUpperInvariant()));
    }
}

public static class MyOperationIdUmbracoBuilderExtensions
{
    public static IUmbracoBuilder ConfigureMyOperationId(this IUmbracoBuilder builder)
    {
        // call this from Program.cs, i.e.:
        //     CreateUmbracoBuilder()
        //         ...
        //         .ConfigureMyOperationId()
        //         .Build();
        builder.Services.AddSingleton<IOperationIdSelector, MyOperationIdSelector>();
        return builder;
    }
}

Adding custom schema IDs

Custom schema IDs can also make it easier for your API consumers to understand and work with your APIs. To that same end, Umbraco applies custom schema IDs to the Umbraco APIs - but not to your APIs.

If you want to create custom schema IDs for your APIs, you must ensure that the Umbraco APIs retain their custom schema IDs. The following code sample illustrates how that can be done.

MySchemaIdSelector.cs
using Umbraco.Cms.Api.Common.OpenApi;

namespace My.Custom.Swagger;

public class MySchemaIdSelector : SchemaIdSelector
{
    public override string SchemaId(Type type)
    {
        // use this if you want to opt into the default Umbraco schema IDs:
        // return UmbracoSchemaId(type);

        // only handle your own types here - make sure to let the base class handle the Umbraco types
        if (type.Namespace?.StartsWith("My.Custom.Api") is false)
        {
            return base.SchemaId(type);
        }

        // build your own logic to generate schema IDs here
        return string.Join(string.Empty, type.FullName!.Replace("My.Custom.Api", string.Empty).Split('.').Reverse());
    }
}

public static class MySchemaIdUmbracoBuilderExtensions
{
    public static IUmbracoBuilder ConfigureMySchemaId(this IUmbracoBuilder builder)
    {
        // call this from Program.cs, i.e.:
        //     builder.CreateUmbracoBuilder()
        //         ...
        //         .ConfigureMySchemaId()
        //         .Build();
        builder.Services.AddSingleton<ISchemaIdSelector, MySchemaIdSelector>();
        return builder;
    }
}

Adding your own Swagger documents

Umbraco automatically adds a "default" Swagger document to contain all APIs that are not explicitly mapped to a named Swagger document. This means that your custom APIs will automatically appear in the "default" Swagger document.

If you want to exercise more control over where your APIs show up in Swagger, you can do so by adding your own Swagger documents.

Umbraco imposes no limitations on adding Swagger documents, and the code below is a simplistic example.

A common use case for this is when you maintain multiple versions of the same API. Often you want to have separate Swagger documents for each version. The following code sample creates two Swagger documents - "My API v1" and "My API v2".

MyConfigureSwaggerGenOptions.cs
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace My.Custom.Swagger;

public class MyConfigureSwaggerGenOptions : IConfigureOptions<SwaggerGenOptions>
{
    public void Configure(SwaggerGenOptions options)
    {
        options.SwaggerDoc(
            "my-api-v1",
            new OpenApiInfo
            {
                Title = "My API v1",
                Version = "1.0",
            });

        options.SwaggerDoc(
            "my-api-v2",
            new OpenApiInfo
            {
                Title = "My API v2",
                Version = "2.0",
            });
    }
}

public static class MyConfigureSwaggerGenUmbracoBuilderExtensions
{
    public static IUmbracoBuilder ConfigureMySwaggerGen(this IUmbracoBuilder builder)
    {
        // call this from Program.cs, i.e.:
        //     builder.CreateUmbracoBuilder()
        //         ...
        //         .ConfigureMySwaggerGen()
        //         .Build();
        builder.Services.ConfigureOptions<MyConfigureSwaggerGenOptions>();
        return builder;
    }
}

With these Swagger documents in place, you can now assign the different versions of your API controllers to their respective documents using the MapToApi annotation.

MyApiController.cs
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Attributes;

namespace My.Custom.Api.V1;

[Route("api/v{version:apiVersion}/my")]
[ApiController]
[ApiVersion("1.0")]
[MapToApi("my-api-v1")]
public class MyApiController : Controller
{
    [HttpGet]
    [Route("do-something")]
    [ProducesResponseType(typeof(MyDoSomethingViewModel), StatusCodes.Status200OK)]
    public IActionResult DoSomething(string value)
        => Ok(new MyDoSomethingViewModel(value));
}

public class MyDoSomethingViewModel
{
    public MyDoSomethingViewModel(string value)
        => Value = value;

    public string Value { get; }
}
MyApiController.cs
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Attributes;

namespace My.Custom.Api.V2;

[Route("api/v{version:apiVersion}/my")]
[ApiController]
[ApiVersion("2.0")]
[MapToApi("my-api-v2")]
public class MyApiController : Controller
{
    [HttpGet]
    [Route("do-something")]
    [ProducesResponseType(typeof(MyDoSomethingViewModel), StatusCodes.Status200OK)]
    public IActionResult DoSomething(string value, int otherValue)
        => Ok(new MyDoSomethingViewModel(value, otherValue));
}

public class MyDoSomethingViewModel
{
    public MyDoSomethingViewModel(string value, int otherValue)
    {
        Value = value;
        OtherValue = otherValue;
    }

    public string Value { get; }

    public int OtherValue { get; }
}

In the you will find comprehensive documentation for Swagger documents.

Swashbuckle.AspNetCore
NSwag
Swashbuckle GitHib repository