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"
"github.com/gradientzero/comby/facade"
)
func main() {
fc := facade.NewFacade()
fmt.Println(comby.PrinInfo(fc))
// notice: application will exit immediately with the following message:
// _______ _____ _______ ______ __ __
// | | | | | | |_____] \_/ » 1.0.0
// |_____ |_____| | | | |_____] | » 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.
Real World Example - with defaults
Click me to view the code
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humachi"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/gradientzero/comby"
combyApi "github.com/gradientzero/comby/api"
combyApiMiddleware "github.com/gradientzero/comby/api/middleware"
combyDomain "github.com/gradientzero/comby/domain"
"github.com/gradientzero/comby/domain/auth"
"github.com/gradientzero/comby/facade"
"github.com/gradientzero/comby/store"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func main() {
// setup stores
eventStore := store.NewEventStoreSQLite("eventStore.db")
commandStore := store.NewCommandStoreSQLite("commandStore.db")
dataStore := store.NewDataStoreFileSystem("./__data__")
// create empty facade
fc := facade.NewFacade(
facade.WithEventStore(eventStore),
facade.WithCommandStore(commandStore),
facade.WithDataStore(dataStore),
)
// register default domains (tenant, account, identity, etc.) to facade
ctx := context.Background()
if err := combyDomain.RegisterDefaults(ctx, fc); err != nil {
panic(err)
}
// register my own domains
// ...
// create new router (chi)
router := chi.NewRouter()
router.Use(middleware.Timeout(30 * time.Second))
router.Use(middleware.Logger)
router.Use(cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
"GET",
"POST",
"PATCH",
"DELETE",
"OPTIONS",
},
AllowedHeaders: []string{
"Accept",
"Authorization",
"Content-Type",
"X-CSRF-Token",
},
ExposedHeaders: []string{
"Link",
},
AllowCredentials: true,
MaxAge: 300,
}).Handler)
router.Use(combyApiMiddleware.AuthorizationToCtx(auth.ApiReadmodel))
router.Use(combyApiMiddleware.PrometheusMiddleware)
router.Mount("/admin", combyApi.AdminDashboardRouter())
router.Mount("/prometheus", promhttp.Handler())
// create new api (huma)
humaCfg := huma.DefaultConfig("My API", "1.0.0")
humaCfg.Components.SecuritySchemes = map[string]*huma.SecurityScheme{
"bearer": {
Type: "http",
Scheme: "bearer",
BearerFormat: "JWT",
},
}
humaApi := humachi.New(router, humaCfg)
// register comby api endpoints
if err := combyApi.RegisterDefaults(fc, humaApi); err != nil {
panic(err)
}
// register own api endpoints
// ...
// restore state
if err := fc.RestoreState(); err != nil {
panic(err)
}
// run http server
fmt.Println(comby.PrinInfo(fc))
http.ListenAndServe("127.0.0.1:8080", router)
// _______ _____ _______ ______ __ __
// | | | | | | |_____] \_/ » 1.0.0
// |_____ |_____| | | | |_____] | » darwin » arm64
// » Working Directory..... /path/to/my/working/directory
// » App Name.............. app
// » Event Store........... sqlite - eventStore.db
// » Command Store......... sqlite - commandStore.db
// » Cache Store........... memory
// » Data Store............ filesystem - __data__
// » Broker................ disabled
// » Email................. disabled
// -----------------------------------------------
// email: admin@comby.io
// password: Placeholder@1
// -----------------------------------------------
}
There are countless variations between the minimal version and a version from a real-world application. In this example we are using SQLite storage for the Events and Commands. We also define the location of the uploaded assets (images, files, etc.).
The defaults
are used here (combyDomain.RegisterDefaults
and combyApi.RegisterDefaults
), which means that the Tenant
, Account
, Groups
, Admin Dashboard
and many other features are available out of the box.
We then build our own chi router and connect it to the endpoints of comby as well as the admin dashboard and our own – yet to be defined – endpoints from the application itself.
comby internally uses huma
, which enables the generation of OpenAPI 3.1
. This is used in real examples to generate TypeScript clients.
The comby defaults initially creates a user with whom you can, for example, log in directly to the admin dashboard or log in for the bearer token.
Open the browser and go to http://localhost:8080/admin
to see the admin dashboard. Login with the provided credentials.