DEV Community

Cover image for SwitchFlow: use your DevCycle account variables as UI toggles in prototyping. Export or download the results
Ogbotemi Ogungbamila
Ogbotemi Ogungbamila

Posted on

SwitchFlow: use your DevCycle account variables as UI toggles in prototyping. Export or download the results

This is a submission for the DevCycle Feature Flag Challenge: Feature Flag Funhouse

What I Built

This is something I am happy to have built and, whether I win or not, I intend to make it into a full-fledged SaaS that opens a new frontier in web development - UI feature flags!.

Problem statement: UI by feature flags

Conditional rendering of web components in React is one thing, prototyping UI's and seeing results directly with the conditional rendering support is another.

Building prototypes and web user interfaces in code editor and saving to see the results in a browser is hard enough without having to apply conditional rendering.

A better approach of using the browser's devtools to directly edit nodes, styles and write scripts is stunted by having no easy save feature and lack supporting conditional rendering without much.

Enter SwitchFlow - a web-based rapid prototyping tool that adds the following to the wheel rather than reinvent it

SwitchFlow's default interface

  • Building UI with feature flags from existing DevCycle account via their API or created, used and stored locally in the service.
  • Quick preview of changes with efficiency and speed
  • Save and resume without user account
  • Pasting complete HTML markup directly in to the DOM
  • Importing existing HTML markup to bootstrap the design process
  • Basic DOM operations - cloning en masse, mutation, traversal, DOM mutation methods and node storage

It is more oriented towards devs but regular users can use its UI feature flagging service.

Demo

Link

https://switch-flow.vercel.app/

Screenshots

Import and export for the web app

import-export section

Dynamic layout grid for 8px-and-above based designs

dynamic layout grid

The initial screen for the UI feature flags

initial screen

Providing API keys to use to obtain and use auth token

provide details

The variables and features loaded via the API

loaded-UI flags

The UI after selecting an environment in a project

UI after choosing environment

After selecting an element to be flagged

after selecting element to toggle

After exporting the page and applying UI flags for previews

after evaluation in exporting
As can be seen when comparing the image above to the ones above it, some sections of its UI have been toggled off.

My Code

GitHub logo ogbotemi-2000 / switch-flow

A rapid prototyping design space with support for a novel feature of UI feature flags

SwitchFlow

A web-based rapid prototyping tool that capitalizes on slapping markups from different sources together, editing and saving them. It is intended to make rapid editing and mutation of nodes possible It sports an excellent idea of directly implementing UI feature flags on the UI prototypes to toggle parts of it on or off.

While it is more developer friendly, regular users can using its UI feature flagging functionality with relative ease.

Feature flags on the UI

It supports connecting a DevCycle account using its client and client secret keys through the API and retrieving all variables defined in each

  • Feature: along with its variations if existent
  • Project: along with each of its environments - staging, development, production

The app was built around the DevCycle API for the DevCycle Feature Flag Challenge challenge For this reason; custom, local flagging support was not prioritized but will be implemented after the challenge…

My DevCycle Experience

Delayed due to missing vital info in API docs.

I got delayed a lot by not quickly realizing how to communicate with the DevCycle API because an important information that connects user account authentication with API operations was missing..

There should be some documentation on what to do with the JSON response (I found out after much stress) returned by the curl command below.
I added a code snippet I use further below in JavaScript to interact with the API after receiving the auth JSON response

curl --request POST \
  --url "https://auth.devcycle.com/oauth/token" \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials \
  --data audience=https://api.devcycle.com/ \
  --data client_id=<client id> \
  --data client_secret=<client secret>
Enter fullscreen mode Exit fullscreen mode

The function I created for obtaining API authentication with consideration for API and network errors

/** This function is defined as async because async functions wrap their return values as promises whose .catch is never called
   * since it wasn't rejected in the first place requiring a boolean check in .then to act as .catch instead
   */

  window.getAuthToken = async function getAuthToken(DEVCYCLE_API_CLIENT_ID, DEVCYCLE_API_CLIENT_SECRET) {
    let error;
    if(getAuthToken.expiresAt > Date.now()) return [getAuthToken.__token, error];
/*window.providerConfig references the form on the page*/
    if(!(DEVCYCLE_API_CLIENT_ID = window.providerConfig.id.value)||!(DEVCYCLE_API_CLIENT_SECRET = window.providerConfig.secret.value)) return;

    return fetch("https://auth.devcycle.com/oauth/token", {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body: new URLSearchParams({
        grant_type: "client_credentials",
        audience: "https://api.devcycle.com/",
        client_id: DEVCYCLE_API_CLIENT_ID,
        client_secret: DEVCYCLE_API_CLIENT_SECRET,
      }),
    }).then(res=>(res.ok||(error=`Request failed due to a HTTP status of ${res.status} for \`https://auth.devcycle.com/oauth/token\`. `), res.json()))
    .then(json=>{
      json.error&&(error &&=error+ `${(json.error_description||'')}${json.error}`),
      getAuthToken.auth = json, getAuthToken.expiresAt = Date.now() + json.expires_in * 1000;
      return [getAuthToken.__token = json.access_token, error]
    }).catch(err=>{
      return [null, 'Unable to make requests to `https://auth.devcycle.com/oauth/token` - you are disconnected from the internet • '+ err.message]
    })
  }
Enter fullscreen mode Exit fullscreen mode

It is used as follows and this is the part actually left out of the documentation

fetch(`https://api.devcycle.com/v1/`, {
    method: args.method,
    headers: {
      "authorization": getAuthToken.__token/** references __token for when getAuthToken gets initialized */,
      "content-type": "application/json"
    },
    ...(args.body&&{body: JSON.stringify(args.body)})
    // body: JSON.stringify({ 'description': "A learning experience on DevCycle's API" })
  }).then(res=>res.json());
Enter fullscreen mode Exit fullscreen mode

The API design is top-notch

Aside the hassle above, I really liked how direct the API is where by some requests only use the HTTP verb they contain to retrieve or set information without bloated request bodies.
Whoever crafted the API knew their craft. Kudos!

The SDK Docs

The docs is missing how to handle JSON variables. I found out by guesswork that the default value needs to be parsed into an object for proper behaviour.

Also, the docs should mention that when targeting is turned off for either development, staging, production environments, the devCycleClient.variableValue call will evaluate the default value passed to it regardless of whether the variable is defined as true or not.
This stumped me for quite a while

Additional Prize Categories

  • API All-Star: I made great use of the API for retrieving SDK keys for all environments, features and variations, variable names

Top comments (0)