Skip to content

Commit

Permalink
doc(main): Updated documentation (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
ekkinox committed Feb 2, 2024
1 parent 3307ab6 commit 2893fc2
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 5 deletions.
Binary file added docs/assets/images/dash-core-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/images/dash-core-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions docs/assets/stylesheets/extra.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#main-image {
background-color: #16181dde;
background-position: center center;
border-radius: 50px;
background-repeat: no-repeat;
display: block;
margin: 0 auto;
}
21 changes: 18 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,23 @@

> Simple, modular, and observable Go framework.
![Image title](assets/images/yokai.png){align=center width="350" height="350"}
![Image title](assets/images/yokai.png){: #main-image width="500" height="500"}

!!! info
The complete Yokai documentation is coming soon !
=== ":fontawesome-solid-face-smile:  Simple"

Yokai is a Go framework that is `easy` to `use`, `configure` and `test`.

With its automatic `dependecy injection system`, you can focus on creating `clean` code.

=== ":fontawesome-solid-cubes:  Modular"

Yokai comes with a `modules plugin system`.

You can enrich your application with the `available modules`, or create `your owns`.


=== ":fontawesome-solid-binoculars:  Observable"

Yokai is focused on `observability`.

It has built-in `logging`, `tracing` and `metrics`, based on [OpenTelemetry](https://opentelemetry.io/) standards.
292 changes: 292 additions & 0 deletions docs/modules/fxcore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
# Core Module

[![ci](https://github.com/ankorstore/yokai/actions/workflows/fxcore-ci.yml/badge.svg)](https://github.com/ankorstore/yokai/actions/workflows/fxcore-ci.yml)
[![go report](https://goreportcard.com/badge/github.com/ankorstore/yokai/fxcore)](https://goreportcard.com/report/github.com/ankorstore/yokai/fxcore)
[![codecov](https://codecov.io/gh/ankorstore/yokai/graph/badge.svg?token=ghUBlFsjhR&flag=fxcore)](https://app.codecov.io/gh/ankorstore/yokai/tree/main/fxcore)
[![Deps](https://img.shields.io/badge/osi-deps-blue)](https://deps.dev/go/github.com%2Fankorstore%2Fyokai%2Ffxcore)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/ankorstore/yokai/fxcore)](https://pkg.go.dev/github.com/ankorstore/yokai/fxcore)

## Overview

Yokai provides a [fxcore](https://github.com/ankorstore/yokai/tree/main/fxcore) module, the heart of your applications.

It comes with:

- a [bootstrapper](https://github.com/ankorstore/yokai/blob/main/fxcore/bootstrap.go)
- a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) system, based on [Fx](https://github.com/uber-go/fx)
- a dedicated core HTTP server
- pre-enabled [Config](fxconfig.mdo), [Health Check](fxhealthcheck.md), [Log](fxlog.md), [Trace](fxtrace.md), [Metrics](fxmetrics.md) and [Generate](fxgenerate.md) modules
- a plugin system for Yokai modules and your own modules

The core HTTP server runs automatically on a dedicated port (default `8081`), to serve:

- the dashboard: UI to get an overview of your application
- the debug endpoints: to expose information about your build, config, loaded modules, etc.
- the health check endpoints: to expose the configured [health check probes](fxhealthcheck.md#probes-registration) of your application
- the metrics endpoint: to expose all [collected metrics](fxmetrics.md#metrics-registration) from your application

Whatever your type of application (HTTP server, gRPC server, worker, etc.), all platform concerns are handled by this
dedicated server:

- to avoid to expose sensitive information (health checks, metrics, debug, etc) to your users
- and most importantly to enable your application to focus on its logic

## Installation

When you use a Yokai [application template](https://ankorstore.github.io/yokai/applications/templates/), you have nothing to install, it's ready to use.

## Usage

### Bootstrap

When you use a Yokai [application template](https://ankorstore.github.io/yokai/applications/templates/), a `internal/bootstrap.go` file is provided.

This is where you can:

- load Yokai or your own modules
- configure the application with any `fx.Option`, at bootstrap on runtime

Example of bootstrap loading the [fxhttpserver](fxhttpserver.md) module:

```go title="internal/bootstrap.go"
package internal

import (
"context"
"fmt"
"testing"

"github.com/ankorstore/yokai/fxcore"
"github.com/ankorstore/yokai/fxhttpserver"
"go.uber.org/fx"
)

func init() {
RootDir = fxcore.RootDir(1)
}

// RootDir is the application root directory.
var RootDir string

// Bootstrapper can be used to load modules, options, services and bootstraps your application.
var Bootstrapper = fxcore.NewBootstrapper().WithOptions(
// fxhttpserver module loading
fxhttpserver.FxHttpServerModule,
// routing
ProvideRouting(),
// services
ProvideServices(),
)

// Run starts the application, with a provided [context.Context].
func Run(ctx context.Context) {
Bootstrapper.WithContext(ctx).RunApp()
}

// RunTest starts the application in test mode, with an optional list of [fx.Option].
func RunTest(tb testing.TB, options ...fx.Option) {
tb.Helper()

tb.Setenv("APP_CONFIG_PATH", fmt.Sprintf("%s/configs", RootDir))

Bootstrapper.RunTestApp(tb, fx.Options(options...))
}
```
Notes:

- the `Run()` function is used to start your application.
- the `RunTest()` function can be used in your tests, to start your application in test mode

### Dependency injection

Yokai is built on top of [Fx](https://github.com/uber-go/fx), offering a simple yet powerful dependency injection system.

This means you don't have to worry about injecting dependencies to your structs, your just need to register their constructors, and Yokai will automatically autowire them at runtime.

For example, if you create an `ExampleService` that has the [config](fxconfig.md) as dependency:

```go title="internal/service/example.go"
package service

import (
"fmt"

"github.com/ankorstore/yokai/config"
)

type ExampleService struct {
config *config.Config
}

func NewExampleService(config *config.Config) *ExampleService {
return &ExampleService{
config: config,
}
}

func (s *ExampleService) PrintAppName() {
fmt.Printf("name: %s", s.config.AppName())
}
```

You then need to register it, by providing its constructor in `internal/services.go`:

```go title="internal/services.go"
package internal

import (
"github.com/foo/bar/internal/service"
"go.uber.org/fx"
)

func ProvideServices() fx.Option {
return fx.Options(
// register the ExampleService
fx.Provide(service.NewExampleService),
// ...
)
}
```

This will make the `ExampleService` available in Yokai's dependency injection system, with its dependencies autowired.

## Configuration

```yaml title="configs/config.yaml"
modules:
core:
server:
port: 8081 # core http server port (default 8081)
errors:
obfuscate: false # to obfuscate error messages on the core http server responses
stack: false # to add error stack trace to error response of the core http server
dashboard:
enabled: true # to enable the core dashboard
overview:
app_env: true # to display the app env on the dashboard overview
app_debug: true # to display the app debug on the dashboard overview
app_version: true # to display the app version on the dashboard overview
log_level: true # to display the log level on the dashboard overview
log_output: true # to display the log output on the dashboard overview
trace_sampler: true # to display the trace sampler on the dashboard overview
trace_processor: true # to display the trace processor on the dashboard overview
log:
headers: # to log incoming request headers on the core http server
x-foo: foo # to log for example the header x-foo in the log field foo
x-bar: bar
exclude: # to exclude specific routes from logging
- /healthz
- /livez
- /readyz
- /metrics
level_from_response: true # to use response status code for log level (ex: 500=error)
trace:
enabled: true # to trace incoming request headers on the core http server
exclude: # to exclude specific routes from tracing
- /healthz
- /livez
- /readyz
- /metrics
metrics:
expose: true # to expose metrics route, disabled by default
path: /metrics # metrics route path (default /metrics)
collect:
enabled: true # to collect core http server metrics, disabled by default
namespace: app # core http server metrics namespace (default app.name value)
subsystem: fx-core # core http server metrics subsystem (default fx-core)
buckets: 0.1, 1, 10 # to override default request duration buckets
normalize: true # to normalize http status code (2xx, 3xx, ...)
healthcheck:
startup:
expose: true # to expose health check startup route, disabled by default
path: /healthz # health check startup route path (default /healthz)
readiness:
expose: true # to expose health check readiness route, disabled by default
path: /readyz # health check readiness route path (default /readyz)
liveness:
expose: true # to expose health check liveness route, disabled by default
path: /livez # health check liveness route path (default /livez)
debug:
config:
expose: true # to expose debug config route
path: /debug/config # debug config route path (default /debug/config)
pprof:
expose: true # to expose debug pprof route
path: /debug/pprof # debug pprof route path (default /debug/pprof)
routes:
expose: true # to expose debug routes route
path: /debug/routes # debug routes route path (default /debug/routes)
stats:
expose: true # to expose debug stats route
path: /debug/stats # debug stats route path (default /debug/stats)
build:
expose: true # to expose debug build route
path: /debug/build # debug build route path (default /debug/build)
modules:
expose: true # to expose debug modules route
path: /debug/modules/:name # debug modules route path (default /debug/modules/:name)
```

Notes:

- the core HTTP server requests logging will be based on the [fxlog](fxlog.md) module configuration
- the core HTTP server requests tracing will be based on the [fxtrace](fxtrace.md) module configuration
- if `app.debug=true` (or env var `APP_DEBUG=true`):
- the dashboard will be automatically enabled
- all the debug endpoints will be automatically exposed
- error responses will not be obfuscated and stack trace will be added

## Dashboard

The core dashboard is available on the port `8081` if `modules.core.server.dashboard=true`:

![](../../assets/images/dash-core-light.png#only-light)
![](../../assets/images/dash-core-dark.png#only-dark)

From there, you can get:

- an overview of your application
- information and tooling about your application: build, config, metrics, pprof, etc.
- access to the configured health check endpoints
- access to the loaded modules information (when exposed)

The core dashboard is made for development purposes, but since it's served on a dedicated port, you can safely decide to leave it enabled on production, not expose it to the public, and access it via [port forward](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) for example.

## Testing

You can start your application in test mode, with the `RunTest()` function provided in the [bootstrapper](#bootstrap).

This wil automatically set the env var `APP_ENV=test`, and [merge your test config](fxconfig.md#dynamic-env-overrides).

It accepts a list of `fx.Option`, for example:

- `fx.Populate()` to extract from the test application autowired components for your tests
- `fx.Invoke()` to execute a function at runtime
- `fx.Replace()` to replace components
- etc.

Test example with `fx.Populate()` :

```go title="internal/example_test.go"
package internal_test

import (
"testing"

"github.com/foo/bar/internal/service"
"github.com/stretchr/testify/assert"
"go.uber.org/fx"
)

func TestExample(t *testing.T) {
var exampleService *service.ExampleService

// run app in test mode and extract the ExampleService
internal.RunTest(t, fx.Populate(&exampleService))

// assertion example
assert.Equal(t, "foo", exampleService.Foo())
}
```

See [Fx documentation](https://pkg.go.dev/go.uber.org/fx) for available options.
2 changes: 1 addition & 1 deletion docs/modules/fxworker.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ This will collect metrics about:
- workers successes
- workers failures

For example, after calling `[GET] /example`, the [fxcore](https://github.com/ankorstore/yokai/tree/main/fxcore) HTTP server will expose in the configured metrics endpoint:
For example, after starting Yokai's workers pool, the [fxcore](https://github.com/ankorstore/yokai/tree/main/fxcore) HTTP server will expose in the configured metrics endpoint:

```makefile title="[GET] /metrics"
# ...
Expand Down
9 changes: 8 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ theme:
toggle:
icon: material/toggle-switch
name: Switch to light mode
logo: 'assets/images/yokai.png'
favicon: 'assets/images/favicon.ico'
features:
- content.code.copy
- content.tabs.link
- navigation.tracking
- navigation.sections
- navigation.top
Expand All @@ -53,8 +53,14 @@ markdown_extensions:
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.tabbed:
alternate_style: true
- tables

# Extra
extra_css:
- 'assets/stylesheets/extra.css'

# Pages tree
nav:
- "Overview": 'index.md'
Expand All @@ -63,6 +69,7 @@ nav:
- "Demos":
- "Showroom": applications/showroom.md
- "Modules":
- "Core": modules/fxcore.md
- "Config": modules/fxconfig.md
- "Generate": modules/fxgenerate.md
- "Health Check": modules/fxhealthcheck.md
Expand Down

0 comments on commit 2893fc2

Please sign in to comment.