JSON2HTML for Edge Delivery Services

Delivering well-structured markup is essential for any AEM site, but when working with a legacy headless CMS, you're often limited to raw JSON responses - far from the clean HTML you're aiming for.

That's where JSON2HTML comes in. This generic worker bridges the gap by transforming JSON data into fully formed HTML pages tailored for Edge Delivery Services.

Best of all, it requires minimal setup - no need to deploy your own service. Here’s how it works…

Usage

Once you have your JSON data, endpoint, and a mustache template to transform JSON into BYOM friendly HTML - then follow these steps to stitch everything together.

"overlay": {
   "url": "https://json2html.adobeaem.workers.dev/<ORG>/<SITE>/<BRANCH>",
   "type": "markup"
 },
POST https://json2html.adobeaem.workers.dev/config/<ORG>/<SITE>/<BRANCH>
Authorization: token <your-admin-token>
Content-Type: application/json
 [
    {
      "path": "/path1/abc/def/",
      "endpoint": "https://<some-endpoint/path>/event-{{id}}.json",
      "regex": "/[^/]+$/",
      "template": "/templates/category/template.html",
      "headers": {
        "X-API-Key": "your-api-key-here",
        "Accept": "application/json"
      },
      "forwardHeaders": [
        "Authorization",
      ],
      "relativeURLPrefix": "https://some-domain.com"
    },
    {
      "path": "/path2/xyz/",
      "endpoint": "https://<another-endpoint/path>/event-{{id}}.json",
      "regex": "/[^/]+$/",
      "template": "/templates/category/template.html"
    }
 ]

Configuration Management

The configuration is managed through a POST request to the /config/:org/:site/:branch endpoint.

Authentication

Request Format

Configuration Structure

The request body should contain an array with one or more configuration objects:

[
  {
    "path": "/path1/abc/def/",
    "endpoint": "https://<some-endpoint/path>/event-{{id}}.json",
    "regex": "/[^/]+$/",
    "template": "/templates/category/template.html",
    "headers": {
      "X-API-Key": "your-api-key-here",
      "Accept": "application/json"
    },
    "forwardHeaders": [
      "Authorization",
    ],
    "relativeURLPrefix": "https://some-domain.com"
  },
  {
    "path": "/path2/xyz/",
    "endpoint": "https://<another-endpoint/path>/event-{{id}}.json",
    "regex": "/[^/]+$/",
    "template": "/templates/category/template.html"
  }
]

Configuration Parameters

Each configuration object in the array requires the following keys:

The worker will:

Example Configuration Updates

Using curl:

curl -X POST \
  https://json2html.adobeaem.workers.dev/config/myorg/mysite/main \
  -H "Authorization: token your-admin-token-here" \
  -H "Content-Type: application/json" \
  -d '[
      {
        "path": "/events/",
        "endpoint": "https://api.example.com/events/{{id}}.json",
        "regex": "/[^/]+$/",
        "template": "/templates/event.html",
        "headers": {
          "X-API-Key": "your-api-key-here"
        },
    "forwardHeaders": [
      "Authorization",
    ],
    "relativeURLPrefix": "https://some-domain.com"
      },
      {
        "path": "/path2/xyz/",
        "endpoint": "https://<another-endpoint/path>/event-{{id}}.json",
        "regex": "/[^/]+$/",
        "template": "/templates/another-mustache-template.html"
      }
    ]'

Example Regex and Endpoint Combinations

"regex": "/\\d+$/"
"endpoint": "https://api.example.com/items/{{id}}.json"

Matches: /products/123, /categories/789

"regex": "/[a-zA-Z0-9-]+$/"
"endpoint": "https://api.example.com/articles/{{id}}"

Matches: /blog/my-article-123, /news/breaking-news

"regex": "/\\d{4}/\\d{2}/\\d{2}/[\\w-]+$/"
"endpoint": "https://api.example.com/archive/{{id}}"

Matches: /posts/2023/12/25/christmas-special

"regex": "/([^/]+)/([^/]+)$/"
"endpoint": "https://api.example.com/{{id}}/details.json"

Matches: /category/subcategory, /region/city

"regex": "/event-([\\w-]+)$/"
"endpoint": "https://api.example.com/events/{{id}}/full"

Matches: /calendar/event-summer-2023, /schedule/event-conf-2024

"regex": "/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/"
"endpoint": "https://api.example.com/records/{{id}}"

Matches: /data/550e8400-e29b-41d4-a716-446655440000

Understanding the relativeURLPrefix Option

The relativeURLPrefix is a configuration option that allows you to rewrite relative URLs in the generated HTML content. This is particularly useful for serving static assets from a CDN or different domain while keeping content URLs relative.

What it does: Automatically adds a custom domain prefix to relative URLs in your HTML content.

Before: <img src="/images/photo.jpg">

After: <img src="https://cdn.example.com/images/photo.jpg">

How to use it: Add “relativeURLPrefix”: “https://your-cdn.com” to your config.

What gets changed: Only URLs that start with / and end with supported file types

What doesn't change: URLs that are already full web addresses or don't match the file type criteria.

Supported File Types: The system only rewrites URLs for these file extensions:

Important Notes

Example Template

The example template below demonstrates how to handle complex JSON structures and conditional rendering using mustache.js syntax.

This template showcases various Mustache patterns:

<!-- Basic variable substitution -->
<title>{{title}}</title>

<!-- Conditional sections -->
{{#hasValues}}
  <!-- Content only rendered if hasValues is true -->
{{/hasValues}}

<!-- Array iteration -->
{{#values}}
  <!-- Content repeated for each item in values array -->
{{/values}}

<!-- Nested object access -->
{{values.0.valueName}}

<!-- HTML content with triple mustache -->
{{{highlights}}}

<!-- Boolean flags for conditional rendering -->
{{#hasConsensus}}
  <!-- Content only rendered if hasConsensus is true -->
{{/hasConsensus}}

Odds and ends

Some meta tags are handled differently in Edge Delivery Services while previewing.

For example, if you want to add a bunch of article:tags, you can do the following in the mustache template:

<meta name="tags" content="{{#tags}}{{.}},{{/tags}}">

and they will be blown up into individual article:tag meta elements in the resulting HTML

FAQ

Why use mustache and not handlebars or more complex templating solutions?
As with everything else in Edge Delivery Services, we strive to make complex interactions as simple and as fast as possible. We use a dependency-free version of Mustache which is a logic-less template syntax that keeps things as simple as possible and results in extremely fast processing times.

What if I want to do some pre/post-processing of the source JSON / resulting HTML for my pages?

What if I have multiple JSONs that I would like to combine into one page in Edge Delivery Services?

How do I develop and test for this without disturbing my production configuration?
Like with everything else in Edge Delivery, this service is also branch-aware. That means you can push a config to a separate branch and use that branch for testing anything you would want to. Once you are satisfied with the testing, then you can push it up the main branch and update the config in the main branch as necessary.