Skip to content

Extension template: Use backoffice JSON options and other fixes#22885

Merged
lauraneto merged 4 commits into
release/18.0from
v18/bugfix/extension-template-api-fixes
May 20, 2026
Merged

Extension template: Use backoffice JSON options and other fixes#22885
lauraneto merged 4 commits into
release/18.0from
v18/bugfix/extension-template-api-fixes

Conversation

@lauraneto

@lauraneto lauraneto commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • The extension template's backoffice API now uses the BackOffice named JsonOptions (both at the controller level via [JsonOptionsName] and at the OpenAPI document via .WithJsonOptions(...)), so the extension's serializer is insulated from consumer-level overrides to the default global JSON options.
  • The sample whoAmI endpoint no longer returns IUser directly. IUser is a Umbraco.Core domain interface, not an API contract — it has no JSON polymorphism configuration and its nested interface properties (e.g. IReadOnlyUserGroup) are not designed to be serialized as part of an HTTP response. Once the BackOffice JSON options activated UmbracoJsonTypeInfoResolver for the extension's OpenAPI document, schema generation produced incomplete output (no type information on the Groups property). The endpoint now projects into a flat WhoAmIResponseModel exposing only the fields the dashboard UI consumes (name, email, groups).
  • Switching the extension template over to AddBackOfficeOpenApiDocument causes the Umbraco schema-ID and operation-ID transformers to run for the extension's document. The previously committed generated client referenced the pre-transform names, so the dashboard would break at type-check / runtime until the SDK was regenerated. The generated client files (Client/src/api/*.gen.ts, index.ts) and the dashboard element are updated accordingly in the same commit.

Testing

Create a new project from the template with the example included (dotnet new umbraco-extension --include-example). Build it against an Umbraco host on v18 and confirm the project compiles and that the OpenApi.json for the Umbraco.Extension document at /umbraco/openapi/umbracoextension.json generates without errors. Launch the backoffice, open the example dashboard, and press the Who am I? button — the notification should display the current user's name and email, and the user's group names should appear in the list.

Then add the following to the consumer site's Program.cs to override the default global JSON options:

// Default MVC JsonOptions (Razor Pages / MVC controllers)
builder.Services.Configure<Microsoft.AspNetCore.Mvc.JsonOptions>(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
});

// Default HTTP JsonOptions (Minimal APIs / OpenAPI schema generation)
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
{
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
});

Re-run the Who am I? button and confirm the response and OpenAPI schema still use BackOffice conventions (camelCase property names) rather than the override — proving the extension's serializer is now insulated from consumer-side global JSON option changes.

Then create a second project from the template without the example (dotnet new umbraco-extension with IncludeExample=false). Confirm the ViewModels/ folder and WhoAmIResponseModel.cs are NOT emitted, the controller compiles without the whoAmI action, and Client/src/dashboards/ is also excluded.

lauraneto added 2 commits May 19, 2026 11:41
…er response with WhoAmIResponseModel

Sets the extension template's backoffice API to use the BackOffice named JsonOptions so the extension's serializer is insulated from consumer-level overrides.

The sample whoAmI endpoint previously returned IUser directly. IUser is a Umbraco.Core domain interface, not an API contract - it has no JSON polymorphism configuration and its nested interface properties (e.g. IReadOnlyUserGroup) are not designed to be serialized as part of an HTTP response. Once the BackOffice JsonOptions activated UmbracoJsonTypeInfoResolver for the extension's OpenAPI document, schema generation produced incomplete output (no type information on the Groups property).

Replaces the return type with a flat WhoAmIResponseModel exposing only the fields the dashboard UI consumes (name, email, groups). Domain interfaces should not be exposed directly on a controller - always project into a dedicated response model.
…o.Extensions import

The composer and controller base referenced `Cms.Core.Constants...` in short form, which relied on namespace fallback from `Umbraco.Extension.Controllers` finding `Umbraco.Cms.Core`. When consumers instantiate the template with a non-Umbraco root namespace, that fallback breaks. References are now fully qualified as `Umbraco.Cms.Core.Constants...`.

Additionally, the `whoAmI` controller's `using Umbraco.Extensions;` was getting mangled by the template engine's token substitution of `Umbraco.Extension` into the consumer's name. Replaces `WhereNotNull()` with the BCL-only `OfType<string>()` so the controller no longer depends on the `Umbraco.Extensions` namespace.
@lauraneto lauraneto marked this pull request as ready for review May 19, 2026 11:02
Copilot AI review requested due to automatic review settings May 19, 2026 11:02
@claude

claude Bot commented May 19, 2026

Copy link
Copy Markdown

Claude encountered an error after 3s —— View job


I'll analyze this and get back to you.

@umbraco umbraco deleted a comment from github-actions Bot May 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Umbraco extension template’s backoffice API to consistently use the BackOffice named JSON options for both runtime serialization and OpenAPI schema generation, and adjusts the example “WhoAmI” endpoint to return an API-friendly response model (plus regenerated client/dashboard updates to match).

Changes:

  • Apply BackOffice named JSON options via [JsonOptionsName] on the controller base and .WithJsonOptions(...) on the template’s BackOffice OpenAPI document.
  • Replace whoAmI returning IUser with a flattened WhoAmIResponseModel (name/email/groups) to avoid serializing domain interfaces.
  • Regenerate/update the template’s TypeScript client + dashboard to align with the new OpenAPI IDs and response model; exclude ViewModels/** when the example isn’t included.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
templates/UmbracoExtension/ViewModels/WhoAmIResponseModel.cs Introduces a dedicated response contract for the whoAmI example endpoint.
templates/UmbracoExtension/Controllers/UmbracoExtensionApiControllerBase.cs Applies BackOffice named JSON options to all derived controllers via [JsonOptionsName].
templates/UmbracoExtension/Controllers/UmbracoExtensionApiController.cs Updates whoAmI to return WhoAmIResponseModel and explicitly supports 204 responses.
templates/UmbracoExtension/Composers/UmbracoExtensionApiComposer.cs Ensures OpenAPI schema generation uses BackOffice named JSON options.
templates/UmbracoExtension/Client/src/dashboards/dashboard.element.ts Updates dashboard to call the regenerated SDK functions and handle the new response shape.
templates/UmbracoExtension/Client/src/api/types.gen.ts Regenerated OpenAPI TS types (new response model + renamed operation types).
templates/UmbracoExtension/Client/src/api/sdk.gen.ts Regenerated SDK with updated operation names and response typing.
templates/UmbracoExtension/Client/src/api/index.ts Re-exports updated SDK functions/types.
templates/UmbracoExtension/Client/src/api/client/utils.gen.ts Regenerated auth helper signature/implementation used by the client.
templates/UmbracoExtension/Client/src/api/client/client.gen.ts Adjusts generated client to match updated setAuthParams call shape.
templates/UmbracoExtension/.template.config/template.json Excludes ViewModels/** when IncludeExample is false.

Comment thread templates/UmbracoExtension/Client/src/dashboards/dashboard.element.ts Outdated
The generated client returns a truthy empty data object (or null body) for a 204 response, so the previous `if (data)` check could pass and render `undefined` values in the notification. Checks `data?.email` instead - it's a required field on a real 200 response and absent in the 204 fallback.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread templates/UmbracoExtension/Client/src/dashboards/dashboard.element.ts Outdated
…dashboard handling

When `BackOfficeSecurity.CurrentUser` is null, the sample `whoAmI` endpoint now returns `Unauthorized()` instead of `NoContent()`, matching the `GetCurrentUserController` pattern in the Management API. Drops the 204 ProducesResponseType so the OpenAPI spec only advertises 200 plus the framework-emitted 401.

The dashboard collapses its empty-data check into a single `error || !data` guard, moves the notification into the success branch, and regenerates the client to drop the now-unused 204 response.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

@lauraneto lauraneto changed the title Extension template: Isolate backoffice JSON options and fix WhoAmI Extension template: Isolate backoffice JSON options and other fixes May 19, 2026
@lauraneto lauraneto changed the title Extension template: Isolate backoffice JSON options and other fixes Extension template: Use backoffice JSON options and other fixes May 19, 2026

@AndyButland AndyButland left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one tiny suggestion @lauraneto - up to you if you think it's useful to update or not. But otherwise all looks good, and I've tested it out. Have successfully created extension with and without the example, and they all build and work as expected. Feel free to merge this when you are ready.

@lauraneto lauraneto merged commit 2f52098 into release/18.0 May 20, 2026
30 checks passed
@lauraneto lauraneto deleted the v18/bugfix/extension-template-api-fixes branch May 20, 2026 08:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants