Chapter 3
The generator turns source declarations into profile YAML.
This page follows the explicit declaration path in the Go demo. It uses real files from the repo and shows enough surrounding code to make each step clear.
1. The application imports the declaration package
The declarations are regular Go calls. They are intentionally no-op at runtime, but the generator can identify them in the AST.
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"strings"
rc "github.com/colinjlacy/golang-ast-inspection/go/runtimeconditions"
)
type Todo struct {
ID int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
2. The app declares the runtime integrations it expects
The API declaration names the catalog entry, the HTTP operation the workload calls, the expected response shape, and the environment variable the app reads.
func init() {
rc.API("todos-api",
rc.Spec("openapi", "catalog://api/default/todos-api", "1.0.0"),
rc.GET("/todos/{id}", rc.Response[Todo]()),
rc.Env("baseUrl", "TODOS_API_URL"),
)
rc.Cache("request-cache",
rc.KeyValue(rc.Redis),
rc.EnvAlternative(rc.Env("url", "REDIS_URL")),
rc.EnvAlternative(
rc.Env("hostname", "REDIS_HOST"),
rc.Env("port", "REDIS_PORT"),
),
)
}
3. The app uses those env vars in normal runtime code
The profile records the names `TODOS_API_URL` and `REDIS_URL`; it does not provide their values. The adapter supplies those later.
func checkTodosAPI(ctx context.Context) error {
baseURL := strings.TrimRight(os.Getenv("TODOS_API_URL"), "/")
if baseURL == "" {
return errors.New("TODOS_API_URL is not set")
}
request, err := http.NewRequestWithContext(
ctx,
http.MethodGet,
baseURL+"/todos/1",
nil,
)
if err != nil {
return err
}
response, err := http.DefaultClient.Do(request)
if err != nil {
return fmt.Errorf("todos-api request failed: %w", err)
}
defer response.Body.Close()
return nil
}
4. The declaration helpers themselves do nothing at runtime
This keeps application behavior unchanged. The generator reads calls to these functions; the compiled service just receives inert values.
// API declares an external API dependency.
func API(name string, options ...APIOption) Declaration {
return Declaration{}
}
// Env declares that a Condition property is supplied through an
// environment variable with the provided name.
func Env(property, name string, options ...EnvOption) ConditionConfigOption {
return ConditionConfigOption{}
}
// Cache declares a cache dependency.
func Cache(name string, options ...CacheOption) Declaration {
return Declaration{}
}
5. Run the generator against the app directory
The generator parses the Go AST, finds the declaration calls, resolves their arguments, and emits a Runtime Conditions Profile.
cd go
go run ./profiler/cmd/runtimeconditions \
-dir ./apps/request-logger-http \
-name request-logger-http \
-workload-uri github.com/example/request-logger-http \
-workload-version v0.1.0
6. The generated profile contains the same requirements
apiVersion: runtimeconditions.io/v1alpha1
kind: RuntimeConditionsProfile
metadata:
name: request-logger-http
workload:
uri: github.com/example/request-logger-http
version: v0.1.0
extensions:
- https://runtimeconditions.io/extensions/common-integrations:v1alpha1
- https://runtimeconditions.io/extensions/env-configuration:v1alpha1
conditions:
- name: todos-api
kind: api
interface:
type: http
spec:
format: openapi
uri: catalog://api/default/todos-api
version: 1.0.0
operations:
- method: GET
path: /todos/{id}
configuration:
env:
- property: baseUrl
name: TODOS_API_URL
- name: request-cache
kind: cache
interface:
type: key_value
engine: redis
configuration:
alternatives:
- env:
- property: url
name: REDIS_URL