Back to Blog

Creating the Linc Demo

How we set up the ultimate demo environment using Linc

Tom Trinca

Background

In creating a demo version of our product, we wanted to change our frontend/backend infrastructure as little as possible, but also end up with a demo version of our production app that would always stay in sync with our production app code.

Before creating our demo, our production app sourced all data from a single GraphQL API endpoint. Ideally, what we wanted was a second API endpoint that would offer the same, albeit read-only operations as our production API endpoint, and then on top of that, a way to instruct our frontend code to use this alternative endpoint when in demo mode.

With Linc environments and stable release preview URLs, implementing this turned out to be easy!

Creating new GraphQL API endpoint

The first thing we changed was our backend API code. Below is a snippet where we created a new GraphQL API endpoint to be used by our demo application:

--CODE:language-js--
app.use(
 '/demo/graphql',
 graphqlExpress((req) => {
   return {
     schema: readOnlySchema,
   }
 })
)

This new GraphQL API uses a schema called readOnlySchema. To create this schema, we duplicated our existing production GraphQL API schema and stripped out all of its mutations leaving only queries, limiting this new demo GraphQL API to read-only operations. Here's an example snippet to give you an idea:

--CODE:language-js--
import { readAndWriteTypeDefs, readOnlyTypeDefs } from './type-defs'
import { queries, mutations } from './resolvers'

import { makeExecutableSchema } from 'graphql-tools'

// production GraphQL schema
export const readAndWriteSchema = makeExecutableSchema({
 typeDefs: readAndWriteTypeDefs,
 resolvers: [...queries, ...mutations], // pass in queries & mutations
})

// demo GraphQL schema
export const readOnlySchema = makeExecutableSchema({
 typeDefs: readOnlyTypeDefs,
 resolvers: [...queries], // only pass in queries
})

We also pass in the authentication credentials of a dummy user account into the GraphQL server context, effectively allowing users of this API to make queries as though they're logged in as the Linc user.

--CODE:language-diff--
app.use(
 '/demo/graphql',
 graphqlExpress((req) => {
   return {
     schema: readOnlySchema,
+      context: {
+        token,
+        user_id
+      },
   }
 })
)

Add Demo Environment

After adding a demo API endpoint, we needed a way to make our frontend conditionally use it instead of our production API endpoint. We started by creating a new Linc environment.

A Linc environment is a set of custom variables that can be injected into your frontend code at runtime. These variables can be used to override various production settings defined in your code, such as an API endpoint.

The variables defined in a given Linc environment are injected into your code at runtime whenever you visit a give Linc preview URL. Linc Preview URLs are special URLs composed of your project's name, a particular version of your code, and a desired Linc environment - this information is used to instruct our infrastructure to deploy a given version of your code against the specified environment:

Preview Link for a particular commit

Another example of a Linc preview URL is deploying the latest released version of your code against a given environment:

Release Preview Link

For our purposes, we created a DEMO environment containing a GRAPHQL_ENDPOINT variable linking to our our new API endpoint:

Demo Environment with one variable

Now, whenever we deploy our code in this DEMO environment, the GRAPHQL_ENDPOINT variable will be automatically injected into our code at runtime.

The next thing we needed to do was edit our frontend code to use this variable.

Using the Demo Environment

As mentioned, Linc environments can be used to override settings defined in your code.

Inline with the FAB documentation, we added a production-settings.json file to our frontend project to contain some default variables to override:

--CODE:language-js--
{
 "GRAPHQL_ENDPOINT": "https://graphql.linc.sh/graphql"
}

Here we defined our a GRAPHQL_ENDPOINT variable with the value of our production GraphQL API endpoint. When your code gets compiled with the FAB compiler, any variables defined in this file get injected into your code at run time just like Linc environments.

So what we're effectively doing here is defining our default API endpoint. We then altered our Apollo Client code to use the GRAPHQL_ENDPOINT variable at runtime:

--CODE:language-js--
import ApolloClient from 'apollo-boost'

// pull endpoint variable out of window object
const GRAPHQL_ENDPOINT = window.FAB_SETTINGS['GRAPHQL_ENDPOINT']

// set URI to endpoint variable
const client = new ApolloClient({
 uri: GRAPHQL_ENDPOINT,
})

export default client

If we run our code in the DEMO environment using the preview links mentioned above, the GRAPHQL_ENDPOINT variable defined in our production-settings.json file will get overridden by the GRAPHQL_ENDPOINT variable defined in the DEMO environment.

Demo friendly UI

The last thing we needed was a way to flag to our UI that it should switch to demo mode so that certain content and functionality could be altered or disabled for a safer demo experience. To do this, we added one new variable DEMO_MODE to our DEMO Environment like so:

Demo Environment with two variables

Then, back in our frontend code, we added a new line to our production-settings.json file as follows:

--CODE:language-diff--
{
 "GRAPHQL_ENDPOINT": "https://graphql.linc.sh/graphql",
+ "DEMO_MODE": false,
}

Here, we define the default value of the DEMO_MODE variable as false, overriding this value to true when we run our code in the DEMO environment.

After adding this extra variable, we created a new file called in our frontend code called config.js to pull out this variable from the window object and export it for use by our UI code.

--CODE:language-js--
export const DEMO_MODE = window.FAB_SETTINGS.DEMO_MODE

We edited a few parts of our UI code to render in a more demo-friendly fashion whenever the value of DEMO_MODE evaluates to true.

And this was our result:

Screenshot of Linc in Demo mode

Summing up

What did we accomplish here?

  • We created a read-only Graphql endpoint, with no mutations, only queries
  • Set up a DEMO environment with our new endpoint and a feature flag DEMO_MODE
  • Changed our frontend code to use FAB_SETTINGS

So what is the benefit of this implementation? Creating a demo version of your application often requires you to spin off separate demo versions of your frontend, database, and APIs. Each duplicated demo piece of infrastructure comes with its' own ongoing maintenance cost. This cost includes the time and energy required to keep the frontend/backend components of your production and demo applications sync.

Our implementation has almost no ongoing maintenance cost. We maintain one version of our frontend code, which has been slightly modified to run in a Linc environment. We maintain one API which exposes a production and a demo GraphQL endpoint, both of which talk to the same production database.

And better yet, for every commit we make to the frontend of our app, Linc gives us preview links against both environments, so we can always make sure both the demo and the production app are working.

Linc Bot comment on Pull Request with two environment links

This is just one example of what Linc environments can help you to build.This is our live demo of Linc. It serves as an example of what you can accomplish with Linc environments. In this blog, we'll cover how Linc environments helped us to create a maintenance-free demo version of our production application with minimal effort.

More from the Blog

Durable Objects in Production

Read how Linc is one of the first products worldwide to use Cloudflare's new serverless real-time data platform.

Read Story

The Future Place

Our tech products could be built with feedback and collaboration from many different experiences. We need to actively and deliberately invite other perspectives into the tech development process.

Read Story

The bottleneck in your frontend development isn't what you think it is

It is way past time to rethink the way we approach CI/CD for frontend applications. We need the automation to not replace humans, but to support them.

Read Story

Linc takes 10 minutes to set up

Start a free 14-day trial now