Yokai Framework
repository·main·Indexed 21 days ago
https://github.com/ankorstore/yokaiA modular, observable Go framework for production-grade backend applications. Yokai automates infrastructure boilerplate including dependency injection via Uber Fx, observability (logging, tracing, metrics), and configuration management. It includes specialized modules such as fxcore for application bootstrapping and a dedicated platform HTTP server, fxconfig for environment-based configuration merging, and fxclock for injectable time manipulation in services and tests.
What's inside Yokai
- The Yokai Http Server module is a wrapper around the Echo web framework. It provides a structured way to set up HTTP servers with built-in support for logging, error handling, various debug handlers, and specialized middlewares.
Overview of Fx Http Server features
mainThe
fxhttpservermodule integrates an HTTP server into your Uberfxapplication. Key features include:- Automatic Panic Recovery: Prevents the server from crashing on unexpected panics.
- Automatic Logging and Tracing: Automatically logs request details such as method, path, and duration.
- Automatic Metrics: Tracks request counts and durations.
- Flexible Registration: Allows for registering individual handlers, handler groups, and middlewares.
- HTML Template Rendering: Built-in support for rendering HTML templates.
Overview of Fx MCP Server features
mainThe
fxmcpservermodule is an Uberfxmodule formark3labs/mcp-go. It allows you to expose a Model Context Protocol (MCP) server from your application with the following built-in capabilities:- Automatic Panic Recovery: Prevents the server from crashing on unexpected errors.
- Observability: Automatic logging and tracing of requests (including method, target, and duration) and automatic metrics (request count and duration).
- Extensibility: Support for registering MCP resources, resource templates, prompts, and tools.
- Server Hooks: Ability to register MCP Streamable HTTP and SSE server context hooks.
- Multiple Transport Options: Expose the MCP server via:
- Streamable HTTP (remote)
- HTTP SSE (remote)
- Stdio (local)
Features of the Fx gRPC Server Module
mainThe
fxgrpcservermodule integrates a gRPC server into an Uberfxapplication, providing several automated capabilities:- Automatic panic recovery: Prevents the server from crashing on unexpected panics.
- Automatic reflection: Enables gRPC reflection for easier debugging and tool integration.
- Automatic logging and tracing: Captures method names, durations, and status codes.
- Automatic metrics: Provides built-in observability for server performance.
- Automatic healthcheck: Integrates health status reporting.
- Extensibility: Allows manual registration of gRPC server options, interceptors, and services.
Overview of the fxcore module
mainThe
fxcoremodule is the central component of a Yokai application. It provides a bootstrapper, a dependency injection system (based on Uber'sFx), and a dedicated core HTTP server.This core HTTP server runs on a dedicated port (default
:8081) and handles platform concerns such as:- Dashboard: A UI for application overview.
- Debug Endpoints: Information about builds, configuration, and loaded modules.
- Health Check Endpoints: Exposes configured health check probes.
- Metrics Endpoint: Exposes collected application metrics.
By using a dedicated server for these concerns, your main application logic remains isolated from platform-level monitoring and debugging traffic.
What is Yokai and how does it work?
mainYokai is a modular and observable Go framework designed to reduce boilerplate in production-grade backend applications. It handles infrastructure concerns like dependency wiring, configuration management, and observability instrumentation so developers can focus on application logic.
Core Architecture
Yokai's architecture is built around three main pillars:
- Core Modules: These modules automatically preload essential infrastructure, including logging, tracing, metrics, and health check instrumentation. They also expose a private HTTP server used for infrastructure management and debugging.
- Extension Modules: These enrich your application with specific features. You can use Yokai's built-in modules, community contrib modules, or your own custom modules. Common extensions include public HTTP/gRPC servers and workers.
- Dependency Injection (DI) System: All modules (core and extensions) are integrated into a central DI system (powered by Uber's
Fx), which you use to wire together your application logic.
Underlying Foundations
Yokai leverages well-known, robust Go libraries to provide its functionality:
- HTTP: Echo
- gRPC: gRPC-go
- Configuration: Viper
- Observability: OTEL (OpenTelemetry)
- Dependency Injection: Fx
Use the Yokai Core Dashboard
mainThe Yokai core module provides a built-in dashboard accessible at
http://localhost:8081. It serves as a central hub for application observability and management.Key features include:
- Application Overview: High-level status of your running service.
- Tooling & Information: Access to build details, configuration inspection, metrics, and
pprofprofiling. - Health Checks: Direct access to configured health check endpoints.
- Module Inspection: View information about loaded modules. For example, the
fxhttpservermodule can expose details such as:- Server port
- Active routes
- Error handler configuration
How the Fx Core module works
mainThe
fxcoremodule serves as the foundation for Yokai applications by providing:- A Bootstrapper: To plug in Fx modules, provide application services, and start the runtime.
- Dependency Injection: Built on top of Uber's
fx. - Core HTTP Server: A dedicated server (default port
:8081) that handles platform concerns separately from your main application logic (e.g., an HTTP or gRPC server). This server exposes:- Dashboard: A UI for application overview.
- Metrics: Endpoint for collected metrics.
- Health Checks: Endpoints for startup, readiness, and liveness probes.
- Debug Endpoints: Information about config, modules, build, and pprof.
This separation ensures that sensitive platform information is not exposed to your end-users and allows your application to focus strictly on business logic.
Use different Span Processors
mainThe module includes four ready-to-use
SpanProcessorimplementations:NewNoopSpanProcessor(): Asynchronously voids trace spans (default behavior).NewStdoutSpanProcessor(options...): Asynchronously prints trace spans to standard output. Accepts options likestdouttrace.WithPrettyPrint().NewOtlpGrpcSpanProcessor(ctx, conn): Asynchronously sends traces to an OTLP/gRPC collector (e.g., Jaeger, Grafana Tempo). Requires a connection created viaNewOtlpGrpcClientConnection(ctx, endpoint).NewTestSpanProcessor(exporter): Synchronously stores traces in memory for testing assertions. Requires an exporter from thetracetestpackage.
Override configuration values via environment variables
mainThe module allows overriding specific configuration keys using environment variables. The mapping follows the pattern
CONFIG_{KEY_NAME}(where the key is converted to uppercase).For example, if you have a configuration key
config.substitution=foo, providing the environment variableCONFIG_SUBSTITUTION=barwill override the value tobar.package main import ( "fmt" "os" "github.com/ankorstore/yokai/config" ) func main() { // Override the 'config.substitution' key os.Setenv("CONFIG_SUBSTITUTION", "bar") cfg, _ := config.NewDefaultConfigFactory().Create() fmt.Printf("substitution: %s", cfg.GetString("config.substitution")) // substitution: bar }Use env var placeholders in configuration files
mainYou can reference environment variables directly within your configuration files using the
${ENV_VAR_NAME}placeholder pattern. These values are resolved at runtime.Example: If your config contains
placeholder: foo-${BAR}-bazand the environment variableBAR=baris set, the resolved value will befoo-bar-baz.Register repositories and services using dependency injection
mainYokai uses automatic dependency injection. To make a repository or service available to other parts of your application, register them in your
internal/register.gofile usingfx.Provide(). This allows the DI container to automatically inject dependencies (like*gorm.DBinto a repository, or a repository into a service) into constructors.func Register() fx.Option { return fx.Options( // services fx.Provide( // gophers repository repository.NewGopherRepository, // gophers service service.NewGopherService, ), ) }