Documentation
¶
Overview ¶
Package reqflow statically traces HTTP request paths through Go codebases.
Given a route like "POST /orders", reqflow finds the handler, follows the call chain through services and stores, and shows exactly which methods are called at each layer — with file names and line numbers.
Install the CLI ¶
go install github.com/ShipOrBleed/reqflow/cmd/reqflow@latest
Trace a request ¶
graph, err := reqflow.Parse(reqflow.ParseOptions{Dir: "."})
if err != nil {
log.Fatal(err)
}
result := reqflow.Trace("POST /orders", graph)
for _, node := range result.Chain {
fmt.Printf("[%s] %s\n", node.Kind, node.Name)
}
List all routes ¶
routes := reqflow.ListRoutes(graph)
for _, r := range routes {
fmt.Printf("%s %s → %s.%s()\n", r.Method, r.Path, r.HandlerName, r.MethodName)
}
Supported frameworks ¶
GoFr, Gin, Echo, Fiber, and net/http handlers are automatically detected. Stores are detected by struct field types (*sql.DB, *gorm.DB, *mongo.Client, etc.), not by naming conventions.
Index ¶
- Variables
- func EdgeLabel(from, to *Node) string
- func ExtractEnvMap(pkgs []*packages.Package, graph *Graph)
- func ExtractGRPC(pkgs []*packages.Package, graph *Graph)
- func ExtractGoModDeps(dir string, graph *Graph)
- func ExtractMiddleware(pkgs []*packages.Package, graph *Graph)
- func ExtractTableMap(pkgs []*packages.Package, graph *Graph)
- func FormatRoutesJSON(routes []RouteInfo) string
- func FormatRoutesText(routes []RouteInfo) string
- func Warn(format string, args ...any)
- type Edge
- type EdgeKind
- type Field
- type Graph
- type MethodCall
- type MethodCallIndex
- type Node
- type NodeKind
- type ParseOptions
- type ReqflowConfig
- type RouteInfo
- type TraceResult
Constants ¶
This section is empty.
Variables ¶
var Version = "dev"
Version is set at build time via ldflags.
Functions ¶
func EdgeLabel ¶
EdgeLabel returns a human-readable description of the transition between two adjacent steps in the trace chain.
func ExtractEnvMap ¶
ExtractEnvMap scans AST for environment variable reads via os.Getenv, os.LookupEnv, and viper.Get* calls. Creates KindEnvVar nodes and EdgeReads edges linking the consuming function/struct to the env var.
func ExtractGRPC ¶
ExtractGRPC detects gRPC service registrations and unimplemented server embeds.
func ExtractGoModDeps ¶
ExtractGoModDeps parses go.mod to identify cloud/infra dependencies.
func ExtractMiddleware ¶
ExtractMiddleware scans for .Use() calls to detect middleware registrations.
func ExtractTableMap ¶
ExtractTableMap inspects KindModel nodes for GORM/sqlx/bson struct tags and creates KindTable nodes representing the inferred database tables, linked via EdgeMapsTo edges.
func FormatRoutesJSON ¶
FormatRoutesJSON renders route info as a JSON array of objects. Each object has fields: method, path, handler, method_name, file, line.
func FormatRoutesText ¶
FormatRoutesText renders route info as an aligned text table suitable for terminal output. Includes a summary line showing total routes and handler count.
Types ¶
type EdgeKind ¶
type EdgeKind string
EdgeKind classifies the relationship between two nodes.
const ( EdgeEmbeds EdgeKind = "embeds" EdgeImplements EdgeKind = "implements" EdgeDepends EdgeKind = "depends" EdgeCalls EdgeKind = "calls" // function-to-function call EdgeFlows EdgeKind = "flows" // request data flow (handler→service→store) EdgeReads EdgeKind = "reads" // reads env var EdgeMapsTo EdgeKind = "maps_to" // model→table mapping EdgeTransitive EdgeKind = "transitive" // transitive dependency EdgePublishes EdgeKind = "publishes" // event publish EdgeSubscribes EdgeKind = "subscribes" // event subscribe EdgeRPC EdgeKind = "rpc" // cross-service RPC call )
type Field ¶
type Field struct{ Name, Type, Tag string }
Field represents a struct field with its name, type, and struct tag.
type Graph ¶
type Graph struct {
Nodes map[string]*Node
Edges []Edge
Clusters map[string][]string // pkg path → []node IDs
Meta map[string]string // graph-level metadata (repo name, commit SHA, etc.)
MethodCalls MethodCallIndex // method-level call index for trace precision
}
Graph is the core data structure representing the architecture of a Go codebase. It contains nodes (components), edges (relationships), and clusters (package groupings).
func Parse ¶
func Parse(opts ParseOptions) (*Graph, error)
Parse loads Go packages from the given directory, walks the AST, and builds a complete architecture graph. It detects handlers, services, stores, models, routes, middleware, gRPC registrations, events, and struct field dependencies.
The resulting Graph can be passed to Trace to follow a specific request path, or to ListRoutes to enumerate all registered HTTP routes.
Example:
graph, err := reqflow.Parse(reqflow.ParseOptions{Dir: "./..."})
if err != nil {
log.Fatal(err)
}
result := reqflow.Trace("POST /orders", graph)
type MethodCall ¶
type MethodCall struct {
FieldName string // e.g. "svc", "store"
TargetMethod string // e.g. "GetMetrics", "GetCostRecords"
}
MethodCall represents a call from one struct method to another struct's method via a struct field. For example, if Handler.GetMetrics() contains the call h.svc.GetMetricsByOrg(), the MethodCall would be {FieldName: "svc", TargetMethod: "GetMetricsByOrg"}.
type MethodCallIndex ¶
type MethodCallIndex map[string][]MethodCall
MethodCallIndex maps "pkg.Struct.Method" → list of outgoing method calls.
type Node ¶
type Node struct {
ID string // "pkg/path.TypeName"
Kind NodeKind
Name string
Package string
Fields []Field
Methods []string
File string
Line int
Meta map[string]string // e.g. "route": "GET /users"
}
Node represents a single component in the architecture graph (struct, interface, function, handler, service, store, model, etc.). Nodes are uniquely identified by their ID (typically "package.TypeName") and carry metadata in the Meta map.
type NodeKind ¶
type NodeKind string
NodeKind classifies a graph node into an architectural layer.
const ( KindStruct NodeKind = "struct" KindInterface NodeKind = "interface" KindFunc NodeKind = "func" KindHandler NodeKind = "handler" // HTTP handler KindStore NodeKind = "store" // DB layer / Repository KindClient NodeKind = "client" // External HTTP/gRPC client KindModel NodeKind = "model" // DB entity / Model KindService NodeKind = "service" // Business logic KindEvent NodeKind = "event" // Event Bus (Kafka/Rabbit) KindMiddleware NodeKind = "middleware" // HTTP Middleware KindGRPC NodeKind = "grpc" // gRPC service KindInfra NodeKind = "infra" // External infrastructure KindRoute NodeKind = "route" // API endpoint KindEnvVar NodeKind = "envvar" // Environment variable KindTable NodeKind = "table" // Database table KindDep NodeKind = "dependency" // go.mod transitive dependency KindContainer NodeKind = "container" // Docker/K8s container KindProtoRPC NodeKind = "proto_rpc" // Proto RPC method KindProtoMsg NodeKind = "proto_msg" // Proto message type )
type ParseOptions ¶
type ParseOptions struct {
// Dir is the Go module directory to analyze. Use "./..." or "." for current directory.
Dir string
// Filter limits analysis to packages matching this substring.
Filter string
// Config is an optional .reqflow.yml configuration. See [LoadConfig].
Config *ReqflowConfig
// EnvMap enables environment variable detection (os.Getenv, viper.Get*).
// Creates KindEnvVar nodes and EdgeReads edges.
EnvMap bool
// TableMap enables model-to-database table mapping from struct tags (gorm, sqlx, bson).
// Creates KindTable nodes and EdgeMapsTo edges.
TableMap bool
}
ParseOptions configures the Parse function.
type ReqflowConfig ¶
type ReqflowConfig struct {
Linter struct {
VetRules []string `yaml:"vet_rules"`
} `yaml:"linter"`
Parser struct {
IgnorePackages []string `yaml:"ignore_packages"`
DomainNaming struct {
ServiceMatch string `yaml:"service_match"`
StoreMatch string `yaml:"store_match"`
ModelMatch string `yaml:"model_match"`
} `yaml:"domain_naming"`
} `yaml:"parser"`
Thresholds struct {
MaxCycles *int `yaml:"max_cycles"`
MaxOrphans *int `yaml:"max_orphans"`
MaxSecurityIssues *int `yaml:"max_security_issues"`
} `yaml:"thresholds"`
// Compiled regexes (not from YAML)
ServiceRegex *regexp.Regexp `yaml:"-"`
StoreRegex *regexp.Regexp `yaml:"-"`
ModelRegex *regexp.Regexp `yaml:"-"`
}
ReqflowConfig represents the .reqflow.yml configuration file. Place this file in your project root to customize layer detection patterns and ignore specific packages.
Example .reqflow.yml:
parser:
ignore_packages:
- vendor
- _test
domain_naming:
service_match: ".*Service$"
store_match: ".*Store$|.*Repository$"
func LoadConfig ¶
func LoadConfig(path string) (*ReqflowConfig, error)
LoadConfig reads and parses a .reqflow.yml configuration file. Returns an error if the file doesn't exist or contains invalid YAML. Regex patterns in domain_naming are compiled into ServiceRegex, StoreRegex, ModelRegex.
type RouteInfo ¶
type RouteInfo struct {
Method string // HTTP method: GET, POST, PUT, DELETE, PATCH
Path string // URL path, e.g. "/orgs/{orgID}/budgets"
HandlerName string // Handler struct name, e.g. "OrderHandler"
MethodName string // Handler method name, e.g. "GetBudgets"
File string // Absolute path to the source file
Line int // Line number where the handler method is defined
}
RouteInfo holds information about a single registered HTTP route, including the handler struct, method name, and source location.
func ListRoutes ¶
ListRoutes extracts all registered HTTP routes from the graph. Routes are sorted by path, then by HTTP method.
Example:
graph, _ := reqflow.Parse(reqflow.ParseOptions{Dir: "."})
routes := reqflow.ListRoutes(graph)
for _, r := range routes {
fmt.Printf("%s %s → %s.%s()\n", r.Method, r.Path, r.HandlerName, r.MethodName)
}
type TraceResult ¶
type TraceResult struct {
// Route is the matched route string, e.g. "POST /orders".
Route string
// Handler is the handler node that owns this route.
Handler *Node
// Chain is the ordered list of nodes in the request path:
// handler → service → store → model, sorted by architectural layer.
Chain []*Node
// Tables lists database table names touched by this request path.
// Populated when -tablemap flag is used.
Tables []string
// EnvVars lists environment variable names read along this request path.
// Populated when -envmap flag is used.
EnvVars []string
// NotFound is true when no handler matched the given route query.
NotFound bool
// CalledMethods maps node ID → list of specific methods called on that node
// in this request path. Only methods actually invoked are included, not all
// methods on the struct.
CalledMethods map[string][]string
// MethodCalls is the full method-level call index, used by renderers
// to display sub-calls (e.g. → svc.GetMetrics()).
MethodCalls MethodCallIndex
// MultiMatch is populated when a path-only query matches multiple HTTP
// methods (e.g. "/orders" → GET /orders, POST /orders). The caller should
// present these options for the user to select one.
MultiMatch []string
}
TraceResult holds the complete request path for a single HTTP route.
When a route is found, Chain contains the ordered list of nodes from handler through service to store, CalledMethods maps each node ID to the specific methods called on it, and MethodCalls provides the full call index for rendering sub-calls.
When multiple routes match a path-only query (e.g. "/orders" matches both GET and POST), MultiMatch is populated instead of Chain, allowing the caller to present a selection to the user.
func Trace ¶
func Trace(route string, g *Graph) *TraceResult
Trace finds the handler matching route and returns the complete static request path through the codebase — handler → service → store → tables, plus any environment variables read along the way.
route may be:
- exact match: "POST /orders"
- path only: "/orders" (matches any HTTP method)
- partial: "orders" (substring match against all registered routes)