Blog
Dioc library in Hoppscotch codebase.

Dioc library in Hoppscotch codebase.

In this article, we review Dioc lbrary in Hoppscotch codebase. We will look at:

  1. What is Hoppscotch?

  2. What is Dioc library?

  3. 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

References:

  1. packages/hoppscotch-selfhost-web/src/services/headerDownloadableLinks.service.ts#L1

  2. https://www.npmjs.com/package/dioc

  3. packages/hoppscotch-selfhost-web/package.json#L41