Terry SmithFront End Engineer @ Manifold

Until recently, the Manifold front end used React with a REST microservice backend, which enabled our developer audience to get up and running quickly with their SaaS services and APIs through our marketplace. On June 6th, 2019, we announced our Marketplace-as-a-Service (MaaS) offering, which helps developer platforms and communities provide the tools developers want in the places they want to build. With this new product it was clear we needed a more flexible UI that lets you browse the catalog or drill into plan selection on existing code bases rather than our own developer dashboard.

In this post I’ll talk about why we chose to add a new framework to our front end stack and migrate our APIs from REST to GraphQL, and I'll walk through a quick tutorial using the new Manifold UI library.

Developer platforms and communities will use MaaS to deliver a first-class buying experience, which means we need a lightweight, portable, and easy to use front-end solution. This can be a very difficult challenge; everyone has their own best practices, favorite frameworks, and individual limitations. Supporting every possible framework was daunting. Our first challenge was to find a framework-agnostic way to ship the Manifold developer experience to anyone, anywhere. After an investigation on this topic, we chose to use Stencil, a TypeScript framework that creates native Web Components.

Web Components: a browser spec we love

It’s a specification that’s been around for years now, but until recently, browser support wasn’t quite production-ready. Web Components enable developers to create custom elements with scoped styled and behavior. Web Components are a browser spec, so you can use the exact same Web Component with React, Vue, Angular, Ember — heck, even vanilla JavaScript! Browser support is great with older browser's polyfill options. See browser support here.

The top priority of this library is something portable,lightweight and fast. Our first version of Stencil components used REST endpoints and also tested the portability aspect. We successfully rolled out the initial version of Manifold UI on three separate code bases and two frameworks. The bundle size was also a big win here compared to the React code it replaced. The initial page load bundle size clocks in at 10.6KB and the loader then lazy loads per component only the needed JavaScript and CSS bundles which are an average of 5KB each. This was an exciting first step, but the REST network requests that needed to load catalog data seemed large and unwieldy in comparison to the slim Stencil bundle.

Moving to greener pastures with GraphQL

A REST call includes everything and the kitchen sink. A request for just the title of a product to render an element will return all the associated information about that product, much more data than necessary for a small component. Some components may also need additional APIs for data which is not included in the initial product call, adding an extra network request and more complex business logic. A GraphQL client on the other hand requests only the data attributes it’s interested in and is able to query additional relational data in a single call, reducing the total number of network calls and the overall size of the received JSON.

We knew we could do better with a few key areas, which meant a big change in our architecture. We started using gRPC, added mandatory pagination and rewrote all database access as part of transitioning to GraphQL. GraphQL responses only send over the requested data in a query. That slashed the amount of bandwidth needed for manifold API calls. The switch to GraphQL also helped with writing more robust components, simplified data responses, and allowed the new Web Components to require less logic to function.

Results and key takeaways

The move to Stencil was the right call. It delivered exactly what was promised and helped make this new offering a practical solution. To load Manifold’s UI library, it’s 10.6KB on initial page load. The move from REST to GraphQL required a lot of work, especially for our backend folks, but the result speaks for itself. At the time of writing we are using 17 Web Components on the new GraphQL endpoints. The latency ranges from +1ms to -82ms response time and network payloads have been significantly reduced by -2.5KB and -217KB compared to their REST counterparts. All these changes combined make UI a lightweight, portable and fast solution to integrate Manifold with existing code bases.

A short tutorial

An average use case needs a catalog listing showing an overview of services available. Once a user finds an interesting service, they can select one to find out more details about the service and what plans are available. After selecting a plan, a user can provision a new service that automatically connects to the service provider, creates a dashboard with SSO support and provides needed environment variables to integrate the service to their codebase immediately.

For this tutorial, we’ll make a basic marketplace on Code Sandbox, which lets you browse service listings, details, and available plans.

Hello Manifold marketplace

To start off let’s look at the most bare-bones catalog listing possible, using some vanilla HTML and a CDN. With this we get a page showing all available services from Manifold. Notice web components are hyphen-separated, not camelCased. This is a telltale sign that something is a native Web Component.

1<!DOCTYPE html>
2<html>
3 <head>
4 <title>Hello Marketplace</title>
5 <meta charset="UTF-8" />
6 <link
7 rel="stylesheet"
8 type="text/css"
9 href="https://js.cdn.manifold.co/@manifoldco/ui/dist/manifold/manifold.css"
10 />
11 </head>
12
13 <body>
14 <manifold-connection></manifold-connection>
15 <manifold-marketplace></manifold-marketplace>
16 <script src="https://js.cdn.manifold.co/@manifoldco/ui/dist/manifold.js"></script>
17 </body>
18</html>

Screen Shot 2019-10-10 at 5.09.11 PM

Vanilla JS Example

Hello Manifold Vue

Vanilla JavaScript is great, but most real-world development uses a front-end framework. For this tutorial, I’ve chosen to use Vue. This is a starter Vue project that uses a package manager, with Manifold UI as a third-party dependency and a Vue router to handle navigation later. The tutorial uses this project as a base.

To initialize Web Component support an app needs to define custom elements once on page load no matter what framework you’re using. I’ve initialized manifold components in src/main.js

1import { defineCustomElements } from "@manifoldco/ui/dist/loader/index.cjs";
2
3defineCustomElements(window);

I’ve also added the manifold-connection component in src/App.vue which is needed to establish a connection to the manifold api servers.

The point where Manifold is visably integrated with Vue is src/components/HelloMarkerplace.vue. With traditional Vue apps, the rendered component lives inside the template tag. The only special thing here is, I’ve loaded a custom element from Manifold UI called manifold-marketplace instead. Notice this is the same custom element used for the vanilla JavaScript example above but I’ve added an attribute hide-templates because we won’t be using them here.

Step 1

Code Example

Product details

Now that we have a basic catalog listing, let’s add product details so we can see more information about each listing. Step one is to get the routing working. Add a new dynamic route to our routes in src/router/index.js which loads the src/components/ManifoldProduct.vue component.

1import ManifoldProduct from "../components/ManifoldProduct.vue";
2
3……
4
5{
6 path: "/product/:product",
7 component: ManifoldProduct
8}

Add an initial Vue component skeleton for ManifoldProduct.vue which will print out the passed product from the router.

1<template>
2 <p>{{$route.params.product}}</p>
3</template>
4
5<script>
6export default {
7 name: "Product"
8};
9</script>

Step two is to make our marketplace link to the shown products. Manifold UI provides custom click events you can easily listen in for which helps with integrations and adding custom logic. The <manifold-marketplace> supports two event types, we’ll be looking at the manifold-marketplace-click event today. In vanilla JavaScript you would listen to this event with something like this:

1document.addEventListener('manifold-marketplace-click', { detail } => {
2 console.log(detail);
3});

Custom events vary a bit by the framework, but it’s generally well documented and should work for Manifold events. For Vue, you add a custom event listener with an @ symbol in the template and provide a method in the default export. Our productSelect method pushes a new route and passes the ‘productLabel’ from the custom event into the newly created dynamic route. The @ is specific to Vue and not needed on other frameworks.

<manifold-marketplace hide-templates @manifold-marketplace-click="productSelect"></manifold-marketplace>

With this work, we can now click on a marketplace listing and get taken to a new page which simply shows the current ProductLabel.

Now, let’s actually load a product detail on this page using a new Manifold UI component. Back on src/components/ManifoldProduct.vue let’s update that template to something more interesting than a ‘p’ tag.

The manifold-product component has a required product attribute called the product-label, so rather than printing out the ‘ProductLabel’ let’s pass that into the manifold-product product-label attribute. The : is specific to Vue. It : binds data passed onto Vue templates.

<manifold-product :product-label="$route.params.product"></manifold-product>

And with that, we now have a product details page for our demo app.

Step 2

Code Example

Showing product plans

Product details give a nice overview of what the service is and links to documentation, support, terms of service documentation and more. But what we don’t know yet is the tier of services offered.

Let’s create a new Vue component and add a new dynamic route to the router.

1import ManifoldPlanSelector from "../components/ManifoldPlanSelector.vue";
2
3
4
5 {
6 path: "/select/:product",
7 component: ManifoldPlanSelector
8 }

Add the Vue component for ManifoldPlanSelector.vue using the manifold-plan-selector Web Component which has the required attribute product-label.

1<template>
2 <manifold-plan-selector :product-label="$route.params.product"></manifold-plan-selector>
3</template>
4
5<script>
6 export default {
7 name: "PlanSelector"
8 };
9</script>

Step 3

Code Example

We now have a three route marketplace, populating data with relatively no Vue configuration. This concludes the tutorial. The logical next step would be to extend the marketplace to provision a resource so a user could start using their new service. While out of scope for this post, this is supported by Manifold UI.

More to learn

This is just one example of the flexibility of the Manifold UI. Check out the Manifold UI documentation and ship your own marketplace today.


Want your own add-ons marketplace?


Stratus Background
StratusUpdate

Sign up for the Stratus Update newsletter

With our monthly newsletter, we’ll keep you up to date with a curated selection of the latest cloud services, projects and best practices.
Click here to read the latest issue.