Dioc library in Hoppscotch codebase.
In this article, we review Dioc lbrary in Hoppscotch codebase. We will look at:
-
What is Hoppscotch?
-
What is Dioc library?
-
Dioc usage in Hoppscotch
I study patterns used in an open source project found on Github Trending. For this week, I reviewed some parts of Hoppscotch codebase and wrote this article.

What is Hoppscotch?
Hoppscotch is an open source API development ecosystem — https://hoppscotch.io. It is an alternative to Postman, Insomnia.
Check out the Hoppscotch documentation to learn more.
What is Dioc library?
dioc is a really simple DI/IOC system where you write services (which are singletons per container) that can depend on each other and emit events that can be listened upon.
Example
import { Service, Container } from "dioc"
// Here is a simple service, which you can define by extending the Service class
// and providing an ID static field (of type string)
export class PersistenceService extends Service {
// This should be unique for each container
public static ID = "PERSISTENCE_SERVICE"
public read(key: string): string | undefined {
// ...
}
public write(key: string, value: string) {
// ...
}
}
type TodoServiceEvent =
| { type: "TODO_CREATED"; index: number }
| { type: "TODO_DELETED"; index: number }
// Services have a built in event system
// Define the generic argument to say what are the possible emitted values
export class TodoService extends Service<TodoServiceEvent> {
public static ID = "TODO_SERVICE"
// Inject persistence service into this service
private readonly persistence = this.bind(PersistenceService)
public todos = []
// Services cannot(*) have constructors, but init logic can be mentioned here
override onServiceInit() {
this.todos = JSON.parse(this.persistence.read("todos") ?? "[]")
}
public addTodo(text: string) {
// ...
// You can access services via the bound fields
this.persistence.write("todos", JSON.stringify(this.todos))
// This is how you emit an event
this.emit({
type: "TODO_CREATED",
index,
})
}
public removeTodo(index: number) {
// ...
this.emit({
type: "TODO_DELETED",
index,
})
}
}
// Services need a container to run in
const container = new Container()
// You can initialize and get services using Container#bind
// It will automatically initialize the service (and its dependencies)
const todoService = container.bind(TodoService) // Returns an instance of TodoService
Check out Dioc npm package.
Dioc usage in Hoppscotch
In headerDownloadableLinks.service.ts, you will find the below code:
/**
* Service to manage the downloadable links in the app header.
*/
export class HeaderDownloadableLinksService
extends Service
implements AdditionalLinkSet
{
public static readonly ID = "HEADER_DOWNLOADABLE_LINKS_SERVICE"
public readonly linkSetID = "HEADER_DOWNLOADABLE_LINKS"
private readonly additionalLinkSet = this.bind(AdditionalLinksService)
/**
* List of downloadable links to be shown in the header
* This includes showing the link to the desktop app, PWA, CLI.
*/
private headerDownloadableLinks = ref<Link[]>([
macOS,
windows,
linux,
pwa,
cli,
])
override onServiceInit() {
this.additionalLinkSet.registerAdditionalSet(this)
}
getLinks(): Ref<Link[]> {
// @ts-expect-error show type not recognizing ComputedRef
return this.headerDownloadableLinks
}
}
onServiceInit function calls registerAdditionalSet function and this additionalLinkSet is imported as shown below, at the top:
import {
AdditionalLinkSet,
AdditionalLinksService,
Link,
} from "@hoppscotch/common/services/additionalLinks.service"
About me:
Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.
Email: ramu.narasinga@gmail.com
I spent 200+ hours analyzing Supabase, shadcn/ui, LobeChat. Found the patterns that separate AI slop from production code. Stop refactoring AI slop. Start with proven patterns. Check out production-grade projects at thinkthroo.com