From 620a673fa3d5527a1ed89d8754f0ab4ec955b958 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 13 Feb 2023 15:16:21 +0100 Subject: [PATCH] A little Monday cleanup (#13823) * Introduce root key constant * Do not enforce ProblemDetails on every non-success response from the API + remove invalid NotFoundResult response types from various endpoints * Update OpenAPI JSON contract to reflect the new NotFound results --- .../ConfigureApiBehaviorOptions.cs | 12 + .../Dictionary/AllDictionaryController.cs | 3 +- .../Dictionary/ExportDictionaryController.cs | 2 +- .../Language/UpdateLanguageController.cs | 2 +- .../ByNameSavedSearchLogViewerController.cs | 2 +- .../DeleteSavedSearchLogViewerController.cs | 2 +- .../Relation/ByIdRelationController.cs | 2 +- .../ManagementApiComposer.cs | 5 +- src/Umbraco.Cms.Api.Management/OpenApi.json | 316 ++---------------- src/Umbraco.Core/Constants-System.cs | 5 + 10 files changed, 59 insertions(+), 292 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiBehaviorOptions.cs diff --git a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiBehaviorOptions.cs b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiBehaviorOptions.cs new file mode 100644 index 0000000000..ac1a98eb9a --- /dev/null +++ b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiBehaviorOptions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace Umbraco.Cms.Api.Common.Configuration; + +public class ConfigureApiBehaviorOptions : IConfigureOptions +{ + public void Configure(ApiBehaviorOptions options) => + // disable ProblemDetails as default result type for every non-success response (i.e. 404) + // - see https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions.suppressmapclienterrors + options.SuppressMapClientErrors = true; +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/AllDictionaryController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/AllDictionaryController.cs index 76af20b0b9..d925985b9e 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/AllDictionaryController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/AllDictionaryController.cs @@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.ViewModels.Dictionary; using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Core; namespace Umbraco.Cms.Api.Management.Controllers.Dictionary; @@ -25,7 +26,7 @@ public class AllDictionaryController : DictionaryControllerBase public async Task>> All(int skip = 0, int take = 100) { // unfortunately we can't paginate here...we'll have to get all and paginate in memory - IDictionaryItem[] items = (await _dictionaryItemService.GetDescendantsAsync(null)).ToArray(); + IDictionaryItem[] items = (await _dictionaryItemService.GetDescendantsAsync(Constants.System.RootKey)).ToArray(); var model = new PagedViewModel { Total = items.Length, diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/ExportDictionaryController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/ExportDictionaryController.cs index 1ffadcd06c..a87c99cef2 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/ExportDictionaryController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/ExportDictionaryController.cs @@ -23,7 +23,7 @@ public class ExportDictionaryController : DictionaryControllerBase [HttpGet("{key:guid}/export")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task Export(Guid key, bool includeChildren = false) { IDictionaryItem? dictionaryItem = await _dictionaryItemService.GetAsync(key); diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Language/UpdateLanguageController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Language/UpdateLanguageController.cs index a2c014c4f4..4ff6e3945b 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Language/UpdateLanguageController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Language/UpdateLanguageController.cs @@ -29,7 +29,7 @@ public class UpdateLanguageController : LanguageControllerBase [HttpPut($"{{{nameof(isoCode)}}}")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task Update(string isoCode, LanguageUpdateModel languageUpdateModel) diff --git a/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/ByNameSavedSearchLogViewerController.cs b/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/ByNameSavedSearchLogViewerController.cs index ef6e062423..d411cca221 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/ByNameSavedSearchLogViewerController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/ByNameSavedSearchLogViewerController.cs @@ -25,7 +25,7 @@ public class ByNameSavedSearchLogViewerController : SavedSearchLogViewerControll /// The saved log search or not found result. [HttpGet("{name}")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(SavedLogSearchViewModel), StatusCodes.Status200OK)] public async Task> ByName(string name) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/DeleteSavedSearchLogViewerController.cs b/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/DeleteSavedSearchLogViewerController.cs index 7ffe8daa74..5f7ae438fe 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/DeleteSavedSearchLogViewerController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/LogViewer/SavedSearch/DeleteSavedSearchLogViewerController.cs @@ -20,7 +20,7 @@ public class DeleteSavedSearchLogViewerController : SavedSearchLogViewerControll /// The result of the deletion. [HttpDelete("{name}")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task Delete(string name) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Relation/ByIdRelationController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Relation/ByIdRelationController.cs index a9ac8cf0cd..c9e8c66430 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Relation/ByIdRelationController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Relation/ByIdRelationController.cs @@ -21,7 +21,7 @@ public class ByIdRelationController : RelationControllerBase [HttpGet("{id:int}")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(RelationViewModel), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task ById(int id) { IRelation? relation = _relationService.GetById(id); diff --git a/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs b/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs index 30b5f13b86..16eeef87b3 100644 --- a/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs +++ b/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs @@ -1,6 +1,3 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Composing; @@ -9,7 +6,6 @@ using Umbraco.Cms.Api.Common.Configuration; using Umbraco.Cms.Api.Common.DependencyInjection; using Umbraco.Cms.Api.Management.DependencyInjection; using Umbraco.Cms.Api.Management.Serialization; -using Umbraco.Cms.Infrastructure.Serialization; using Umbraco.Cms.Web.Common.ApplicationBuilder; using Umbraco.New.Cms.Core.Models.Configuration; @@ -45,6 +41,7 @@ public class ManagementApiComposer : IComposer services .ConfigureOptions() + .ConfigureOptions() .Configure(options => { options.AddFilter(new UmbracoPipelineFilter( diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 42262ac2d2..53f5c67367 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -80,14 +80,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -125,14 +118,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -167,14 +153,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -222,14 +201,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -269,14 +241,7 @@ "description": "Created" }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -316,14 +281,7 @@ "description": "Success" }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -364,14 +322,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -435,14 +386,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -467,14 +411,7 @@ "description": "Success" }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -512,14 +449,7 @@ "description": "Success" }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -733,14 +663,7 @@ "description": "Created" }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" }, "400": { "description": "Bad Request", @@ -798,14 +721,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -840,14 +756,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -895,14 +804,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -945,14 +847,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResultModel" - } - } - } + "description": "Not Found" } } } @@ -1002,14 +897,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -1048,14 +936,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -1488,14 +1369,7 @@ ], "responses": { "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Unauthorized" }, "200": { "description": "Success", @@ -1538,14 +1412,7 @@ ], "responses": { "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Unauthorized" }, "200": { "description": "Success", @@ -1791,14 +1658,7 @@ ], "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" }, "200": { "description": "Success", @@ -1835,14 +1695,7 @@ ], "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" }, "200": { "description": "Success", @@ -2285,14 +2138,7 @@ }, "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" }, "400": { "description": "Bad Request", @@ -2328,14 +2174,7 @@ ], "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" }, "200": { "description": "Success", @@ -2424,14 +2263,7 @@ }, "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResultModel" - } - } - } + "description": "Not Found" }, "400": { "description": "Bad Request", @@ -2768,14 +2600,7 @@ ], "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResultModel" - } - } - } + "description": "Not Found" }, "200": { "description": "Success", @@ -2810,14 +2635,7 @@ ], "responses": { "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResultModel" - } - } - } + "description": "Not Found" }, "200": { "description": "Success" @@ -3049,14 +2867,7 @@ ], "responses": { "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Unauthorized" }, "200": { "description": "Success", @@ -3099,14 +2910,7 @@ ], "responses": { "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Unauthorized" }, "200": { "description": "Success", @@ -4037,14 +3841,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResultModel" - } - } - } + "description": "Not Found" } } } @@ -4805,14 +4602,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -4850,14 +4640,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -4892,14 +4675,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } }, @@ -4947,14 +4723,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -5042,14 +4811,7 @@ } }, "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetailsModel" - } - } - } + "description": "Not Found" } } } @@ -7854,16 +7616,6 @@ } } }, - "NotFoundResultModel": { - "type": "object", - "properties": { - "statusCode": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, "OkResultModel": { "type": "object", "properties": { diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs index 43de01995b..24820e58b4 100644 --- a/src/Umbraco.Core/Constants-System.cs +++ b/src/Umbraco.Core/Constants-System.cs @@ -18,6 +18,11 @@ public static partial class Constants /// Use this instead of re-creating the string everywhere. public const string RootString = "-1"; + /// + /// The GUID identifier for global system root node. + /// + public static readonly Guid? RootKey = null; + /// /// The integer identifier for content's recycle bin. ///