Episerver ServiceAPI: Create a custom endpoint


In some cases, you uploaded an asset through Service API.
And then you want to update its properties later. You can create a custom endpoint to implement it and we want to reuse the authentication, routing  of ServiceAPI:
using EPiServer.ServiceApi.Configuration;
using EPiServer.ServiceApi.Validation;
using EPiServer.ServiceApi.Commerce.Controllers.Catalog;
using ControllerBase = EPiServer.ServiceApi.Commerce.Controllers.Catalog.ControllerBase;
using AuthorizePermissionAttribute = EPiServer.ServiceApi.Configuration.AuthorizePermissionAttribute;
using EPiServer.ServiceApi.Commerce;
using Foundation.Features.Media;
using EPiServer.DataAccess;
using EPiServer.Security;
using System.Configuration.Provider;

namespace Foundation.Custom
{
    [Route("episerverapi/commerce")]
    [RequireHttpsOrClose]
    [ValidateReadOnlyMode(AllowedVerbs = HttpVerbs.Get)]
    [ExceptionHandling]
    [RequestLogging]
    [Authorize(Policy = "ServiceApiAuthorizationPolicy")]
    public class ItemAssetController : ControllerBase
    {
        private readonly IdentityMappingService _identityMappingService;
        private readonly ReferenceConverter _referenceConverter;
        private readonly IContentRepository _contentRepository;

        public ItemAssetController(
            IdentityMappingService identityMappingService,
            ReferenceConverter referenceConverter,
            IContentRepository contentRepository,
            IContentLoader contentLoader,
            IContentVersionRepository contentVersionRepository) : base(contentLoader, contentVersionRepository)
        {
            _identityMappingService = identityMappingService;
            _referenceConverter = referenceConverter;
            _contentRepository = contentRepository;
        }

        [Route("entries/{entryCode}/assets/{assetKey:guid}/properties/categories", Name = "SetAssetCategoriesByEntry")]
        [HttpPut]
        [AuthorizePermission("EPiServerServiceApi", "WriteAccess")]
        public virtual IActionResult SetAssetCategoriesByEntry([FromEntryCode("entryCode")] string entryCode, Guid assetKey, [FromBody] string[] categories)
        {
            var mappedIdentity = _identityMappingService.Get(assetKey);
            //mappedIdentity = _identityMappingService.Get(MappedIdentity.ConstructExternalIdentifier(providerName, integrationId));

            if (mappedIdentity == null)
                return NotFound($"No mapping found for asset with ID {assetKey} on entry {entryCode}");

            var contentLink = _referenceConverter.GetContentLink(entryCode);

            var entryContentBase = _contentLoader.Get<EntryContentBase>(contentLink);

            var commerceMedia =
                entryContentBase.CommerceMediaCollection.FirstOrDefault(media => media.AssetLink.ID == mappedIdentity.ContentLink.ID);

            if (commerceMedia == null || !_contentRepository.TryGet<ImageMediaData>(commerceMedia.AssetLink, out var genericMedia))
                return NotFound();

            genericMedia = (ImageMediaData) genericMedia.CreateWritableClone();
            genericMedia.ImageCategories = categories;

            _contentRepository.Save(genericMedia, SaveAction.Publish, AccessLevel.NoAccess);

            return Ok();
        }
    }
}


For the background, you could look at the table tblMappedIdentity, we can retrieve the content link from asset key (or integrationId):



Time to test our API, I prefer to use the CURL format that can be imported to postman:
curl --location --request PUT 'https://localhost:5001/episerverapi/commerce/entries/P-39813617/assets/24D74AD3-4E22-4AD3-9AD5-A88153DE2CA5/properties/categories' \
--header 'Content-Type: application/json' \
--header 'Authorization: bearer {token}' \
--header 'Accept: application/json' \
--header 'Cookie: EPiServer_Commerce_AnonymousId=c6e42968-1bfc-4310-af77-2ca9e4af5eed; EPiStateMarker=true; Language=en' \
--data ' ["cat1", "cat2"]'



If you don't know how to get a token, please refer to this post: https://khanhpham2411.blogspot.com/2023/12/serviceapi-example-of-how-to-properly.html

For the idea of next endpoint,  you can use the provider name and intergrationId.


Comments

Popular posts from this blog

Optimizely Content Graph: minimal setup for testing

Episerver ServiceAPI: Example of how-to properly call the media upload

SameSite Cookie login troubleshooting