Contentful logo

Contentful Community

How to convert the response from Get a single entry API to html for the Rich Text values

Hi there,
I’m using the Get a single entry API to get the value from Rich Text to my application where I would like to have the values formatted as applied in the Rich Text of Contentful. Below is the response from the API:
image
I would like to know how to convert the response from Get a single entry API to html for the Rich Text values. Could someone help with this? Thanks!

Regards,
Diyab

If you are using javascript, you can use the @contentful/rich-text-html-renderer.

Hi Jaymie,
Thank you for the reply. I’m new to contentful, you mean this @contentful/rich-text-html-renderer - npm? I’m not using Javascript. Is there any API which passes the HTML in the json node or any other solution? Thanks!

No there isn’t (that I know of), but it’s actually not that hard to write something yourself.
Here is my code, I am sure you can convert it to whatever language you want:

    import { DirectiveBinding } from "vue/types/options";

    export const content = {
      bind(el: HTMLElement, binding: DirectiveBinding): void {
        const { value } = binding;
        const openMarks = {
          bold: true,
          italic: true,
          underline: true,
        };
        const html = parseHtmlString(value, openMarks);
        el.innerHTML = html;
      },
    };

    type nodeType =
      | "document"
      | "text"
      | "paragraph"
      | "hr"
      | "unordered-list"
      | "ordered-list"
      | "hyperlink";
    type mark = "bold" | "underline" | "italic";

    interface Content {
      nodeType: nodeType;
      content: ContentItem[];
      data: any;
    }

    interface OpenMark {
      bold: boolean;
      italic: boolean;
      underline: boolean;
    }

    interface ContentItem extends Content {
      marks: any[];
      value: string;
    }

    function parseHtmlString(content: Content[], openMarks: OpenMark): string {
      //console.log(JSON.parse(JSON.stringify(content)));
      let htmlString = "";
      content.forEach((item: Content) => {
        //console.log(JSON.parse(JSON.stringify(item)));
        switch (item.nodeType) {
          case "hr":
            htmlString += "<hr />";
            break;
          case "unordered-list":
            htmlString += `<ul>${parseListItem(item.content, openMarks)}</ul>`;
            break;
          case "ordered-list":
            htmlString += `<ol>${parseListItem(item.content, openMarks)}</ol>`;
            break;
          default:
            htmlString += `<p>${parseChildren(item.content, openMarks)}</p>`;
            break;
        }
      });
      return htmlString;
    }

    function parseListItem(items: ContentItem[], openMarks: OpenMark): string {
      return items
        .map(
          (item: ContentItem) =>
            `<li>${parseHtmlString(item.content, openMarks)}</li>`
        )
        .join("");
    }

    function parseChildren(items: ContentItem[], openMarks: OpenMark): string {
      return items
        .map((item: ContentItem) => {
          //console.log(console.log(JSON.parse(JSON.stringify(item))));
          switch (item.nodeType) {
            case "hyperlink":
              return formatHyperlink(item);
            default:
              return formatMarks(item, openMarks);
          }
        })
        .join("");
    }

    function formatMarks(item: ContentItem, openMarks: OpenMark): string {
      //console.log(console.log(JSON.parse(JSON.stringify(item))));
      let text = item.value?.trim();
      if (!item?.marks?.length) return `${text} `;

      const marks = item.marks.map((item: any) => item.type);

      marks.forEach((mark: mark) => {
        switch (mark) {
          case "bold":
            text = formatMark("strong", text, openMarks.bold);
            if (!item.value) openMarks.bold = !openMarks.bold;
            break;
          case "italic":
            text = formatMark("i", text, openMarks.italic);
            if (!item.value) openMarks.italic = !openMarks.italic;
            break;
          case "underline":
            text = formatMark("u", text, openMarks.underline);
            if (!item.value) openMarks.underline = !openMarks.underline;
            break;
        }
      });

      return `${text} `;
    }

    function formatMark(mark: string, text: string, isOpen: boolean) {
      if (text) return `<${mark}>${text}</${mark}>`;

      return isOpen ? `<${mark}>` : `</${mark}>`;
    }

    function formatHyperlink(content: ContentItem) {
      const email = isEmail(content.data.uri);
      const text = content.content.find(
        (content: any) => content.nodeType === "text"
      );

      if (email) {
        return `<a href="${content.data.uri}" data-category="contact" data-action="email">${text.value}</a>`;
      }

      const outbound = isExternal(content.data.uri);

      if (outbound) {
        return `<a href="${content.data.uri}" data-category="navigate" data-action="outbound link">${text.value}</a>`;
      } else {
        return `<a href="${content.data.uri}" data-category="navigate" data-action="inbound link">${text.value}</a>`;
      }

      function isExternal(url: string): boolean {
        const links = url.split("#");
        const href = links[0] || ".";

        return (
          href.indexOf("http://") === 0 ||
          href.indexOf("https://") === 0 ||
          href.indexOf("www.") === 0
        );
      }

      function isEmail(url: string): boolean {
        return url.toLowerCase().indexOf("mailto") > -1;
      }
    }