ApiBlaze: Development Phases

Inception

The development of ApiBlaze started like so many other projects with a simple npm init in two folders called backend and frontend.

Prototype

In the course of about 6 weeks, we implemented the following functions and features:

  • Backend: Parse API spec and provide an optimized, internal datamodel for searching
  • Frontend: Dispatch and process WebSocket requests for searching in the internal datamodel
  • Frontend: Display search results in a popup
  • Frontend: Display description and referenced request/response datastructure of the selected element
  • Backend: Introduce the concept of clients, store client ID and currently selected API
  • Frontend and Backend: Search and select different OpenAP specification
  • Frontend: Switch search mode between properties, objects and endpoints, and render search results visually different
<section class="search-wrapper">
<h2>Search</h2>
<div class="input-wrapper">
<input type="text" id="query" value="" spellcheck="false" />
</div>
...
</section>
$query.focus()function addCollapses($container) {
...
}
$query.addEventListener('input', event => {
let value = event.target.value
search();
})
socket.on('results', results => {
renderResults(results)
})
function copy(text) {
...
}
$query.addEventListener('keyup', resultsKeyControl)
$query.addEventListener('focus', resultsFocusCheck)
$query.addEventListener('blur', resultsFocusCheck)

Modularization

After the long summer break, interests shifted and my friend could no longer contributed to the project. I took torch and continued the development, but was unable to add substential new features because of the code base.

import { handleApiSearch } from '../controller.js'let state = {}
let _$root = undefined
function updateState (newState) {
state = { ...state, ...newState }
}
function getState () {
return state
}
function render (args) {
const html = `
<h2>Load an API</h2>
<input type="text" class="api-search-bar" id="api-search-bar" value="" spellcheck="false">
<div id="api-search-results" class="api-search-results"></div>
`
return html
}
function mount ($root, ...args) {
_$root = $root
$root.innerHTML = render(args)
document
.getElementById('api-search-bar')
.addEventListener('keyup', e => handleKeyup(e))
}
function refresh (args) {
mount(_$root, args)
}
function handleKeyup (e) {
console.log(e)
const keyword = e.target.value
handleApiSearch(keyword, updateState)
}
export { mount, getState, refresh }

Framework-Based Design

Following the substantial overhaul during modularization, one thing still bothered me: code duplication. Essentially, each component and page had the same methods included. I could not fathoom a simple solution to extract the duplicate methods into a seperate module, and import from there. So I started to define classes for pages and components — code duplication nicely eliminated, and now each object has a standard interface that I can use. And now, when the controller deals with standardized object, the jump to a framework is not far.

import { Component } from 'spac'import SearchApiAction from '../actions/SearchApiAction.js'export default class SearchBarComponent extends Component {
render = () => {
return `
<input type="text" id="api-search-query" value="${this.getState()
.apiSearchQuery || 'Kubernetes'}" spellcheck="false">
`
}
mount () {
super.mount()
document
.querySelector('#api-search-query')
.addEventListener('keyup', e => this.handleKeyUp(e, this))
}
handleKeyUp (e) {
e.preventDefault()
this.updateState({ apiSearchQuery: e.target.value })
his.triggerSearch()
}
async triggerSearch (e) {
const apiList = await new SearchApiAction().run()
this.updateState({ apiList })
}
}

Conclusion

This article explained the three development phases of ApiBlaze. During inception, we explored how to connect the frontend and backend with WebSockets. In the early prototype, we added the main feature: searching for API elements with immediate update of the UI, displaying the description and foldable data models, and much more. After a long break, the code base was overhauled by me — first to a module based implementation, and then with using classes it evolved to a custom framework. The ApiBlaze blog series will be paused, and I continue with explaining the framework.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store