How to Develop and Deploy Custom Request/Response Filters for Data Transformation in INFINI Gateway
INFINI Gateway enables data transformation at the edge by implementing the pipeline.Filter interface, registering the component via pipeline.RegisterFilterPluginWithConfigMetadata, and declaring it in the gateway.yml flow configuration.
Developing custom request/response filters for data transformation in INFINI Gateway requires implementing a Go interface that intercepts HTTP traffic within the proxy's pipeline architecture. The gateway processes every request through an ordered sequence of filters defined in common/flow.go, allowing you to modify headers, rewrite bodies, or enrich context data before the request reaches the upstream backend. Because filters are compiled into the binary as native Go code, they execute with minimal overhead while maintaining full access to the fasthttp request context.
Understanding the Filter Architecture
INFINI Gateway organizes traffic processing into flows, each consisting of an ordered slice of filters. At runtime, GetFlow (defined in common/flow.go) loads the flow definition and assembles a FilterFlow struct containing the filter chain【link-filterflow】.
The FilterFlow.Process method iterates over each filter, invoking the Filter(ctx *fasthttp.RequestCtx) method while respecting the request's continuation flags【link-process】. This architecture ensures that filters execute sequentially unless explicitly halted or skipped.
Key structural components include:
pipeline.Filterinterface – The contract requiringName() stringandFilter(ctx *fasthttp.RequestCtx)methodsFilterConfig– Configuration model defined incommon/entry.gothat maps YAML parameters to filter instances【link-filterconfig】- Registration system – Global registry populated via
pipeline.RegisterFilterPluginWithConfigMetadata, as demonstrated inproxy/output/queue/queue.go【link-queue-register】
Implementing the pipeline.Filter Interface
Custom filters must satisfy the pipeline.Filter interface defined in the framework core. Create a Go struct that holds configuration fields and implements the required methods.
package custom
import (
"infini.sh/framework/core/config"
"infini.sh/framework/core/pipeline"
"infini.sh/framework/lib/fasthttp"
"log"
)
// HeaderFilter adds a static header to the response.
type HeaderFilter struct {
HeaderName string `config:"header_name"` // Maps to YAML parameter
HeaderValue string `config:"header_value"` // Maps to YAML parameter
}
// Name satisfies the pipeline.Filter interface.
func (f *HeaderFilter) Name() string { return "custom_header" }
// Filter implements the transformation logic.
func (f *HeaderFilter) Filter(ctx *fasthttp.RequestCtx) {
if f.HeaderName == "" {
log.Printf("custom_header filter: header_name not set")
return
}
ctx.Response.Header.Add(f.HeaderName, f.HeaderValue)
}
The Filter method receives a pointer to fasthttp.RequestCtx, providing full access to request headers, body, response objects, and custom context values. Because this executes on the hot path, avoid blocking operations; use asynchronous clients for external service calls.
Registering Your Custom Filter
After implementing the interface, register the filter with the pipeline registry so the gateway can instantiate it from configuration. Place the registration in an init() function within the same package.
func init() {
// RegisterFilterPluginWithConfigMetadata registers the constructor and
// extracts configuration metadata from the empty instance.
pipeline.RegisterFilterPluginWithConfigMetadata(
"custom_header", // Name referenced in gateway.yml
NewHeaderFilter, // Constructor function
&HeaderFilter{}, // Empty instance for config parsing
)
}
// NewHeaderFilter constructs a HeaderFilter from the generic config.
func NewHeaderFilter(c *config.Config) (pipeline.Filter, error) {
f := &HeaderFilter{}
if err := c.Unpack(&f); err != nil {
return nil, err
}
return f, nil
}
The constructor pattern used here mirrors the implementation found in proxy/output/queue/queue.go, where built-in filters register themselves using the same API【link-queue-register】. The config.Config parameter contains the parameters map defined in your YAML configuration.
Configuring the Flow in gateway.yml
Declare your custom filter within a flow definition to activate it. The gateway.yml file (or any loaded configuration source) defines flows under the flows key, specifying filters as an ordered array.
flows:
my_custom_flow:
filter:
- name: custom_header
parameters:
header_name: "X-Customer-ID"
header_value: "12345"
- name: logging # Built-in filters chain seamlessly
When the gateway starts, the flow loader creates each filter instance via its registered constructor, passing the parameters map to NewHeaderFilter. The resulting FilterFlow processes requests through your custom logic before executing subsequent filters like the built-in logging handler.
Building and Deploying the Custom Filter
Deploying custom filters requires compiling the code into the gateway binary, as INFINI Gateway statically links all filter implementations.
-
Place the source file – Add your Go package under
proxy/filters(e.g.,proxy/filters/custom/header.go) to maintain consistency with built-in filters likeproxy/filters/transform/set_header.go. -
Recompile the binary – Execute
makeorgo build ./...from the repository root. The initialization code automatically registers your filter during package import. -
Update configuration – Edit
gateway.ymlto reference the new filter name in your target flow. -
Restart or reload – Start the compiled binary. The flow loader in
main/main.goparses the configuration and instantiates your filter. If the gateway runs with hot-reloading enabled, editinggateway.ymltriggers a flow reload without restarting the process, provided the filter code is already compiled into the running binary.
Summary
Custom request/response filters for data transformation in INFINI Gateway extend the proxy's capabilities through compiled Go code:
- Implement the
pipeline.Filterinterface withName()andFilter(ctx *fasthttp.RequestCtx)methods - Register the filter using
pipeline.RegisterFilterPluginWithConfigMetadatato enable YAML-based instantiation - Configure flows in
gateway.ymlusing the filter name and parameter map defined in your struct tags - Deploy by recompiling the binary and restarting the service, leveraging hot-reload for configuration changes
This pattern allows you to inject headers, transform request bodies, route traffic based on custom logic, or integrate with external systems while maintaining the high-performance characteristics of the underlying fasthttp framework.
Frequently Asked Questions
What Go interface must a custom filter implement in INFINI Gateway?
A custom filter must implement the pipeline.Filter interface, which requires two methods: Name() string returning the filter identifier, and Filter(ctx *fasthttp.RequestCtx) containing the transformation logic. The Filter method receives the request context from the fasthttp library, allowing manipulation of headers, body, and response objects.
How does INFINI Gateway load and execute custom filters at runtime?
The gateway loads filters through the GetFlow function in common/flow.go, which constructs a FilterFlow containing an ordered slice of pipeline.Filter instances【link-filterflow】. When processing requests, FilterFlow.Process iterates over this slice, calling each filter's Filter method sequentially while checking continuation flags【link-process】. Filters execute in the order defined in the gateway.yml configuration file.
Can custom filters access configuration parameters from gateway.yml?
Yes, filters receive configuration through struct tags and the constructor pattern. Define configuration fields in your filter struct with `config:"parameter_name"` tags, then register the filter using pipeline.RegisterFilterPluginWithConfigMetadata. The constructor receives a *config.Config object containing the parameters map from gateway.yml, which you unpack into your struct using c.Unpack(&filterInstance).
Where should custom filter source files be placed in the repository?
Place custom filter source files within the proxy/filters directory to maintain alignment with the project's architecture. Built-in examples like proxy/filters/transform/set_header.go demonstrate the expected package structure. After adding your files, recompile the gateway binary using make or go build to statically link your filter into the executable.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →