Part 2: Run comby
comby is a powerful framework that offers the user many options. On the one hand, the so-called defaults
from comby can be used, which offer the user ready-made domains
such as Tenant
, Account
, Groups
, Admin Dashboard
and so on or the user is completely free to start from scratch. In this guide, we will show you how to start comby with the defaults
.
TIP
Further information on the options for configuring comby as needed can be found in the documentation. The starting point is: Documentation
Minimal Example - completely blank
package main
import (
"fmt"
"github.com/gradientzero/comby/v2"
)
func main() {
fc, _ := comby.NewFacade()
fmt.Println(fc.PrintInfo())
// notice: application will exit immediately with the following message:
// _______ _____ _______ ______ __ __
// | | | | | | |_____] \_/ » x.y.z
// |_____ |_____| | | | |_____] | » darwin » arm64
// » Working Directory..... /path/to/my/working/directory
// » App Name.............. app
// » Event Store........... memory
// » Command Store......... memory
// » Cache Store........... memory
// » Data Store............ memory
// » Broker................ disabled
// » Email................. disabled
}
Even the output to the console is optional, but this just shows how to create a new facade. However, not much is happening here yet. Usually there is a listener - for example an HTTP listener - that ensures that the application can accept and process HTTP requests. The newly created facade can then be tackled.
Simple Example - with defaults
// simple/main.go
package main
import (
"context"
"fmt"
"net/http"
"comby.io/examples/simple/api"
"comby.io/examples/simple/domain"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humago"
"github.com/gradientzero/comby/v2"
combyApi "github.com/gradientzero/comby/v2/api"
combyDomain "github.com/gradientzero/comby/v2/domain"
"github.com/gradientzero/comby/v2/web"
)
func main() {
// create empty facade
fc, _ := comby.NewFacade()
// register comby domains
if err := combyDomain.RegisterDefaults(context.Background(), fc); err != nil {
panic(err)
}
// register my domains
if err := domain.RegisterDomains(context.Background(), fc); err != nil {
panic(err)
}
// restore state
if err := fc.RestoreState(); err != nil {
panic(err)
}
// create new mux
mux := http.NewServeMux()
// add comby admin dashboard
mux.Handle("/admin/", web.AdminHandler())
// add custom router handleFunc
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`hello world`))
})
// create huma api
humaApi := humago.New(mux, huma.DefaultConfig("My API", "1.0.0"))
// add comby's default api
if err := combyApi.RegisterDefaults(fc, humaApi); err != nil {
panic(err)
}
// add our custom api
if err := api.RegisterEndpoints(fc, humaApi); err != nil {
panic(err)
}
fmt.Println(fc.PrintInfo())
http.ListenAndServe("127.0.0.1:8080", mux)
}
There are countless variations between the minimal version and a version from a real-world application. In this example we are just using memory storage for the Events and Commands. The so called defaults
are used here (combyDomain.RegisterDefaults
and combyApi.RegisterDefaults
), which means that the all predefined domains like Tenant
, Account
, Group
, Authorization
, Admin Dashboard
and many others are available out of the box. In addition we register our own, custom domains to the Facade
(domain.RegisterDomains
). The Facade
is the central point of the application. Once all domains are registered we can restore the state of the application from the event store (fc.RestoreState
).
Since we want to use a REST API by default, we continue with creating the router. comby internally uses huma
, which enables the generation of OpenAPI 3.1
. This is used in real examples to generate TypeScript clients. So after we register the corresponding comby api defaults
(combyApi.RegisterDefaults
), we can continue with our own api endpoints (api.RegisterEndpoints
).
Since we use huma
in both cases, a common REST API is generated and is available at runtime as http://localhost:8080/api/openapi.yaml
. This is automatically used to provide an interactive REST API Explorer
at http://localhost:8080/docs/api
. We also connect the comby Admin Dashboard
and can access it via http://localhost:8080/admin
.
At the initial start, predefined credentials that can also be overwritten by environment variables are displayed:
...
-----------------------------------------------
email: admin@comby.io
password: Placeholder@1
-----------------------------------------------
You can use them to login into the Admin Dashboard
. By using Dev Tools you can also extract the Authorization Header, which is a Bearer Token. This token can be used to authenticate against the REST API Explorer.
INFO
We have not setup any email provider, nor any other external services. In a real world example, you would use a persistent storage like SQLite or Postgres. Further information about Configuration can be found in the documentation: Configuration
eventStore = store.NewEventStoreSQLite("/path/to/sqlite/file.db")
eventStore = store.NewEventStorePostgres("host", port, "user", "password", "db")
Let's create a new domain using an example and learn how comby works.