Static deployments without IFrame URLs

This is a guest post by Callum McIntyre. You can follow him on twitter at @callum_codes

GraphJSON has two options for embedding a chart into your website both discussed in previous guides: you can generate static IFrame URLs that can be included directly in your code or you can make an API call to generate an iFrame URL for a customised set of parameters.

At first glance it looks like there's a tradeoff here: if your parameters are fixed then you can avoid making an API call on every request and speed up your website/enable static deployments - if you embed IFrame URLs in your code. That's not a problem if you just have one or two charts, but can become unwieldy if you have many.

When I wrote the first version of my running dashboard I used embedded IFrame URLs, but found it difficult to keep track of a whole dashboard of them as I kept adding and experimenting with new ideas. I also found that iterating was a bit slower when I needed to go to the GraphJSON dashboard to generate new charts instead of just changing parameters in my code.

The good news is that modern frameworks can remove this tradeoff, letting us deploy a static website without dealing with IFrame URLs in our code.

Goals

Here's what we want to achieve:

  • A dashboard with our GraphJSON dashboards embedded
  • No IFrame URLs in our code
  • No API calls made when the page loads

Just show me the code!

If you're already familiar with NextJS and getStaticProps then here's a CodeSandbox demonstrating the pattern: https://codesandbox.io/s/graphjson-getstaticprops-58wu0. Just fork it and set the GRAPHJSON_API_KEY secret key to use your own data.

Otherwise read on and we'll build it together!

NextJS

NextJS is a React framework that works hard to optimise our pages as much as possible: if they don't need to make any API calls in order to render, then it will simplify them to static HTML and Javascript that loads super fast and can be deployed on any CDN. No need for any server-side rendering. That makes it perfect for a dashboard where all the charts have fixed config.

If you'd like to follow along, you can generate a NextJS project. Just run npx create-next-app.

We'll start by writing a function to generate an IFrame URL. Here's an example of how that might look (using GraphJSON's Export > as Dynamic IFrame)

// lib/graphjson.js

export async function getCountIframeUrl() {
  const payload = {
    api_key: process.env.GRAPHJSON_API_KEY,
    IANA_time_zone: "America/Los_Angeles",
    graph_type: "Single Line",
    start: "1 month ago",
    end: "now",
    filters: [],
    metric: null,
    aggregation: "Count",
    compare: "",
    granularity: "Auto",
    customizations: { lineColor: "#987DE3", secondaryColor: "#9CA3AF" }
  };

  const response = await fetch(
    "https://www.graphjson.com/api/visualize/iframe",
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload)
    }
  );
  const jsonResponse = await response.json();
  return jsonResponse.url;
}

// Other functions to generate more GraphJSON charts...

I've just put the generated code into a function getCountIframeUrl in lib/graphjson.js

Notice that we're using an environment variable here for the API key, because of course we don't want to check that in to source control. So we can't call this function from the client which doesn't have the API key, and we don't want to call it from the server on every request. So where do we call it? That's where getStaticProps comes in.

getStaticProps

If a NextJS page exports a function getStaticProps then the page will be pre-rendered using the props returned by that function. You can read more about this in the NextJS docs. In other words, the function will be run only at build time, on your local machine or wherever you build your code, and the result will be used to render a static HTML page that makes no API calls.

Here's how a component looks using this:

// pages/index.js

import { getCountIframeUrl } from "../lib/graphjson";

export async function getStaticProps() {
  const countIframeUrl = await getCountIframeUrl();
  // await other iframe URL functions

  return {
    props: {
      countIframeUrl
      // other generated iframe URLs
    }
  };
}

export default function IndexPage(props) {
  return (
    <iframe
      title="count of events"
      src={props.countIframeUrl}
      style={{
        padding: "15px",
        height: "300px",
        width: "600px",
        border: "1px solid #9CA3AF"
      }}
    />
  );
}

That's all the code that we need to write. We have functions in lib/graphjson.js that generate IFrame URLs from our parameters, so that we don't need to put them in our code. And we have pages that import those functions, call them in getStaticProps and use the resulting URLs to render IFrames within the page.

Next build

When running NextJS locally (or in CodeSandbox) you'll notice that it runs the functions in getStaticProps on every page load. But that's not the behaviour that we'll have in production. We can see this by generating a production build. Make sure your .env.local file includes GRAPHJSON_API_KEY=... with your API key set. Note that this file is not checked in!

$ npx next build
info  - Loaded env from .env.local
info  - Using webpack 5. Reason: Enabled by default https://nextjs.org/docs/messages/webpack5
info  - Checking validity of types  
info  - Creating an optimized production build  
info  - Compiled successfully
info  - Collecting page data  
info  - Generating static pages (3/3)
info  - Finalizing page optimization  

Page                              Size     First Load JS
┌ ● /                             2.9 kB         66.6 kB
├   /_app                         0 B            63.7 kB
└ ○ /404                          3.18 kB        66.8 kB
+ First Load JS shared by all     63.7 kB
  ├ chunks/framework.64eb71.js    42 kB
  ├ chunks/main.655ad0.js         20.3 kB
  ├ chunks/pages/_app.8f10d9.js   556 B
  ├ chunks/webpack.672781.js      766 B
  └ css/7e1a3392e7b78569e048.css  3.06 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)

Notice that our / page has been automatically rendered as static HTML. You can see this generated page in .next/server/pages/index.html - you'll be able to see that the GraphJSON IFrame URLs are included directly in the HTML.

If you just want to experiment though, feel free to fork my CodeSandbox example which should now look familiar! Just remember to set your GRAPHJSON_API_KEY secret key so that it can generate IFrame URLs for your data.

The easiest way to deploy NextJS for free is on Vercel, just make sure you set the GRAPHJSON_API_KEY environment variable there and they'll generate and cache this optimised build for you.

GraphJSON by @JRTheBuilder

© GraphJSON 2021