A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Dylan Barter
Sep 6, 2023
  1314
(0 votes)

Optimizely Configured Commerce Custom POST API

Introduction

When creating custom API controllers for an Optimizely B2B project it’s possible you’ll want to create POST calls. Following the architecture of the base code you will likely have a controller that inherits from the BaseApiController and utilizes ExecuteAsync or Execute methods to map your parameters and results and run a service method.

What can sometimes go unnoticed is that any result you’d like to return from a POST call requires a populated “Uri” string field on your result model.  This is because the Optimizely BaseApiController will not return the API result model with the POST response if the model doesn’t have a Uri value or it is null or blank. See the code section below from the BaseApiController Execute method:

            if (this.Request.Method == HttpMethod.Post)
            {
                if (apiResult.Uri.IsBlank())
                {
                    return this.StatusCode(HttpStatusCode.Created);
                }

                return this.Created(apiResult.Uri, apiResult);
            }

You can see that without a Uri parameter on the apiResult object, the method will simply return a “Created” status code as the result and omit the actual apiResult object payload.  So, if you are seeing empty results from your custom POST method, it’s likely you have not properly set the Uri field and the object is being left off the response.  If your response model inherits from BaseModel, then it already has a Uri parameter and you simply need to set it, likely in your mapper.  Several of the Optimizely B2B API flows will set the Uri parameter in the mapper, like the AccountsV1 endpoint does in GetAccountMapper:

        public virtual AccountModel MapResult(
            AddAccountResult serviceResult,
            HttpRequestMessage request
        )
        {
            var accountModel = this.GetAccountMapper.MapResult(
                serviceResult.GetAccountResult,
                request
            );

            accountModel.Password = accountModel.IsGuest ? serviceResult.Password : string.Empty;
            accountModel.BillToId = serviceResult.BillTo.Id;
            accountModel.ShipToId = serviceResult.ShipTo.Id;

            accountModel.Uri = this.UrlHelper.Link(
                "AccountV1",
                new { accountid = Constants.WebApiCurrent },
                request
            );

            return accountModel;
        }

The Uri should accurately identify the way that object could be resourced.  In this case, the UrlHelper.Link method returns the Get Account method which includes the Account Id. 

Sep 06, 2023

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP - OptiGraphExtensions v2.0: Enhanced Search Control with Language Support, Synonym Slots, and Stop Words

Supercharge your Optimizely Graph search experience with powerful new features for multilingual sites and fine-grained search tuning. As search...

Graham Carr | Dec 16, 2025

A day in the life of an Optimizely OMVP - Optimizely Opal: Specialized Agents, Workflows, and Tools Explained

The AI landscape in digital experience platforms has shifted dramatically. At Opticon 2025, Optimizely unveiled the next evolution of Optimizely Op...

Graham Carr | Dec 16, 2025

Optimizely CMS - Learning by Doing: EP09 - Create Hero, Breadcrumb's and Integrate SEO : Demo

  Episode 9  is Live!! The latest installment of my  Learning by Doing: Build Series  on  Optimizely Episode 9 CMS 12  is now available on YouTube!...

Ratish | Dec 15, 2025 |

Building simple Opal tools for product search and content creation

Optimizely Opal tools make it easy for AI agents to call your APIs – in this post we’ll build a small ASP.NET host that exposes two of them: one fo...

Pär Wissmark | Dec 13, 2025 |