SaaS CMS has officially launched! Learn more now.

MartinOttosen
Mar 1, 2024
  5310
(5 votes)

Headless forms reloaded (beta)

Forms is used on the vast majority of CMS installations. But using Forms in a headless setup is a bit of pain since the rendering pipeline is based on ASP.NET MVC. We do have an extension to our Content Delivery API that includes the generated forms HTML in the json model for a page, but if you want the frontend to control the look & feel of the rendered form, you’re fighting an uphill battle. Better then if Forms could just expose the raw forms configuration with a handy front-end SDK with a good default rendering.

Note: This feature is in Beta, you are welcome to use it, but we do have more changes coming before the official release. Beta packages will be removed once official packages are released.

What's in it?

  1. Forms 5 [package] [docs]
  2. New REST API [beta package] [beta docs]
  3. (optional) Graph integration [beta package] [beta docs]
  4. (optional) generic JS SDK [beta package] [beta docs] [repo]
  5. (optional) react specific SDK [beta package] [beta docs] [repo]

As a quick example I created the worlds least interesting form using a boilerplate Alloy MVC site, which yes is not headless, but that’s the point really. This is just good-old-forms under the hood.

With a reference to the headless forms beta feed we can add the new REST API and optionally swashbuckle:

<PackageReference Include="EPiServer.Forms" Version="5.8.0" />
<PackageReference Include="Optimizely.Headless.Form.Service" Version="0.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />

Getting the new endpoint setup is pretty easy, we need to add a service to startup.cs for the new API and optionally a service + some configuration for swagger:

// Enable OpenAPI documentation
services.AddSwaggerGen();

//Configure the API headless forms API
services.AddOptimizelyHeadlessFormService(options =>
{
    // Enable swagger docs for headless forms API @ /_form/v1/docs/openapi.json
    options.EnableOpenApiDocumentation = true;

    options.FormCorsPolicy = new FormCorsPolicy
    {
        AllowOrigins = new string[] { "_" }, //Enter '_' to allow any origins, multiple origins separate by comma 
        AllowCredentials = true
    };
});

 

// Configure swagger UI to use the headless forms API spec
app.UseSwagger();
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/_form/v1/docs/openapi.json", "Optimizely Headless Form API V1");
});

With that we get nice local documentation of the API available at /swagger/. In production you would probably want to configure OIDC for access to endpoints and docs.

To get the full form configuration you pass in the GUID of the form container in UUID N format i.e. without any “-“ separators

GET /_form/v1/form/2df32b30ade54eb3970e4ab5170fb5ff

{
  "key": "2df32b30ade54eb3970e4ab5170fb5ff",
  "properties": {
    "title": "test",
    "allowToStoreSubmissionData": true,
    "showSummarizedData": false,
    "confirmationMessage": "Thank you, come again!",
    "allowAnonymousSubmission": false,
    "allowMultipleSubmission": true,
    "showNavigationBar": true,
    "focusOnForm": true
  },
  "formElements": [
    {
      "key": "2697b674ec554f7a817ea1f977fc2204",
      "contentType": "TextboxElementBlock",
      "displayName": "New form element",
      "properties": {
        "validators": [
          {
            "type": "RequiredValidator",
            "description": null,
            "model": {
              "message": "This field is required.",
              "validationCssClass": "ValidationRequired",
              "additionalAttributes": {
                "required": "",
                "aria-required": "true"
              }
            }
          }
        ],
        "label": "Name",
        "placeHolder": "firstname lastname",
        "conditions": []
      },
      "locale": "en",
      "localizations": {}
    },
    {
      "key": "3aa836ec620146cf8291263c51b4b44f",
      "contentType": "SubmitButtonElementBlock",
      "displayName": "New form element",
      "properties": {
        "validators": [],
        "label": "Go!",
        "conditions": []
      },
      "locale": "en",
      "localizations": { "label": "Submit" }
    }
  ],
  "locale": "en",
  "localizations": {
    "allowAnonymousSubmissionErrorMessage": "You must be logged in to submit this form. If you are logged in and still cannot post, make sure \"Do not track\" in your browser settings is disabled.",
    "allowMultipleSubmissionErrorMessage": "You already submitted this form.",
    "malformstepconfigruationErrorMessage": "Improperly formed FormStep configuration. Some steps are attached to pages, while some steps are not attached, or attached to content with no public URL."
  }
}

Installing the Forms to Graph integration of course requires Optimizely Graph, and will simply add a new property “FormRenderTemplate” to the Graph model for a FormContainerBlock exposing the exact same json object available from the REST API.

query MyQuery {
  FormContainerBlock {
    items {
      FormRenderTemplate
    }
  }
}

If we want to upgrade to a completely decoupled frontend we can use the react sample from the new forms SDK repository, but I think that warrants it’s own blog post.

Besides any notes you may have here or at feedback.optimizely.com for this beta release, we have plans to update the current authorization system for form submitters and refine the SDK to give you a better looking starting point.

Mar 01, 2024

Comments

Janne Tuutti
Janne Tuutti Jun 12, 2024 07:39 AM

Hi, when is the estimated time of arrival for the final product? 

Please login to comment.
Latest blogs
Optimizely SaaS CMS Concepts and Terminologies

Whether you're a new user of Optimizely CMS or a veteran who have been through the evolution of it, the SaaS CMS is bringing some new concepts and...

Patrick Lam | Jul 15, 2024

How to have a link plugin with extra link id attribute in TinyMce

Introduce Optimizely CMS Editing is using TinyMce for editing rich-text content. We need to use this control a lot in CMS site for kind of WYSWYG...

Binh Nguyen Thi | Jul 13, 2024

Create your first demo site with Optimizely SaaS/Visual Builder

Hello everyone, We are very excited about the launch of our SaaS CMS and the new Visual Builder that comes with it. Since it is the first time you'...

Patrick Lam | Jul 11, 2024

Integrate a CMP workflow step with CMS

As you might know Optimizely has an integration where you can create and edit pages in the CMS directly from the CMP. One of the benefits of this i...

Marcus Hoffmann | Jul 10, 2024

GetNextSegment with empty Remaining causing fuzzes

Optimizely CMS offers you to create partial routers. This concept allows you display content differently depending on the routed content in the URL...

David Drouin-Prince | Jul 8, 2024 | Syndicated blog

Product Listing Page - using Graph

Optimizely Graph makes it possible to query your data in an advanced way, by using GraphQL. Querying data, using facets and search phrases, is very...

Jonas Bergqvist | Jul 5, 2024