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
- 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
Dynamic layout grid for 8px-and-above based designs
The initial screen for the UI feature flags
Providing API keys to use to obtain and use auth token
The variables and features loaded via the API
The UI after selecting an environment in a project
After selecting an element to be flagged
After exporting the page and applying UI flags for previews
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
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>
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]
})
}
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());
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)