How do I wire services and components together in an EK9 application?

← Web Services · Ref: Q203

EK9 applications wire services and components together using 'register' declarations. Programs access injected components with the '!' suffix.

COMPONENT DEFINITION

Define abstract and concrete components:

  defines component
    Repository as abstract
      findAll() as abstract
        <- rtn as List of String?
    InMemoryRepo extends Repository
      override findAll()
        <- rtn <- List() of String

APPLICATION REGISTRATION

Register concrete components and services:

  defines application
    MyApp
      register InMemoryRepo() as Repository
      register ItemService()

PROGRAM WITH APPLICATION

Link a program to an application for injection:

  MyProgram() with application of MyApp
    repo as Repository!

The '!' suffix injects the registered Repository.

WIRING ORDER

The application definition controls which implementations satisfy abstract dependencies. The compiler validates that all injection points can be satisfied.

See Q111 for component basics. See Q112 for service basics. See Q199 for REST endpoints. See Q114 for aspects. See Q227 for compile-time DI validation. See Q228 for registration ordering. See Q231 for program-application linking.

Example

defines module qa.web.application

  defines component

    Repository as abstract
      findAll() as abstract
        <- rtn as List of String?

      default operator ?

    InMemoryRepo extends Repository
      override findAll()
        <- rtn <- List() of String
        rtn += "item1"
        rtn += "item2"

      default operator ?

  defines service

    ItemService :/items open

      listAll() :/
        <- response as HTTPResponse: () with trait HTTPResponse
          override content()
            <- rtn as String: `{"items": []}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: "application/json"
          override cacheControl() as pure
            <- rtn as String: "no-cache"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    MyApp
      register InMemoryRepo() as Repository
      register ItemService()

  defines program

    AppWiringDemo() with application of MyApp
      stdout <- Stdout()

      repo as Repository!

      items <- repo.findAll()
      for item in items
        stdout.println(`Item: ${item}`)

      stdout.println("Components and services wired via application")

Common mistakes

E50060 — Repository does not have a getAll() method. The correct method name is findAll(). Using the wrong method name triggers E50060 — method not resolved. See ek9 -h E50060 for details.

Incorrect:

items <- repo.getAll()

Correct:

items <- repo.findAll()
Other ways to ask this
  • How does application registration work in EK9?
  • How do I connect services and components in EK9?
  • How do I use dependency injection with services in EK9?

Coming from another language?

Java: Spring @Configuration with @Bean definitions, @Autowired injection. Python: FastAPI Depends() or manual DI. Rust: no built-in DI. Go: manual wiring or wire codegen. Kotlin: Koin module { single { } } or Dagger @Module. EK9: 'register X() as Y' in application definition, '!' suffix for injection.

Keywords: component, register, http, wire, service, rest, application, dependency, inject, compose