API Reference
API Reference
Complete documentation for all Roamer components.
Table of Contents
Core API
Roamer
The main Roamer struct that orchestrates parsing, decoding, and formatting.
Constructor
func NewRoamer(opts ...OptionsFunc) *Roamer
Create a new Roamer instance with the specified options.
Options:
WithParsers(parsers ...Parser)
- Add parsers for different request partsWithDecoders(decoders ...Decoder)
- Add decoders for request bodiesWithFormatters(formatters ...Formatter)
- Add formatters for post-processingWithSkipFilled(skip bool)
- Control whether to skip fields with non-zero values (default: true)WithAssignExtensions(extensions ...assign.ExtensionFunc)
- Register custom assignment extensionsWithPreserveBody()
- Enable request body preservation for multiple reads
Note on WithPreserveBody()
: When enabled, the request body is read into memory and can be read multiple times. This is useful for logging, validation, or when multiple parsers/decoders need to access the body. However, it may impact performance for large request bodies as the entire body is stored in memory.
Methods
func (r *Roamer) Parse(req *http.Request, ptr any) error
Parse an HTTP request into the provided struct pointer.
Parameters:
req
- HTTP request to parseptr
- Pointer to struct that will receive parsed data
Returns: Error if parsing fails
Context Functions
func ParsedDataFromContext(ctx context.Context, ptr any) error
Extract parsed data from request context (used with middleware).
Parsers
Parsers extract data from different parts of HTTP requests.
Query Parser
Parse query parameters from the URL.
func NewQuery(opts ...QueryOption) *Query
Options:
WithSplitSymbol(symbol string)
- Set symbol for splitting array values (default: “,”)WithDisabledSplit()
- Disable automatic splitting of values
Struct Tag: query:"parameter_name"
Example:
type Request struct {
Page int `query:"page"`
Tags []string `query:"tags"` // Splits "tag1,tag2,tag3"
Search string `query:"q"`
}
Header Parser
Parse HTTP headers.
func NewHeader() *Header
Struct Tag: header:"Header-Name"
or header:"Header1,Header2"
(fallback)
Example:
type Request struct {
UserAgent string `header:"User-Agent"`
Language string `header:"Accept-Language,Accept-Lang"`
Token string `header:"Authorization"`
}
Cookie Parser
Parse HTTP cookies.
func NewCookie() *Cookie
Struct Tag: cookie:"cookie_name"
Example:
type Request struct {
SessionID string `cookie:"session_id"`
Theme string `cookie:"theme"`
UserID string `cookie:"user_id"`
}
Path Parser
Parse path parameters (requires router integration).
func NewPath(pathFunc PathValueFunc) *Path
PathValueFunc signature:
type PathValueFunc func(req *http.Request, paramName string) (string, bool)
Struct Tag: path:"parameter_name"
Example:
type Request struct {
ID string `path:"id"`
Category string `path:"category"`
}
Router Integrations:
- Chi:
parser.NewPath(rchi.NewPath(router))
- Gorilla:
parser.NewPath(rgorilla.Path)
- HttpRouter:
parser.NewPath(rhttprouter.Path)
Decoders
Decoders handle request body parsing based on Content-Type.
JSON Decoder
Parse JSON request bodies.
func NewJSON(opts ...JSONOption) *JSON
Options:
WithContentType[T](contentType string)
- Custom content type (default: “application/json”)
Struct Tag: json:"field_name"
XML Decoder
Parse XML request bodies.
func NewXML(opts ...XMLOption) *XML
Options:
WithContentType[T](contentType string)
- Custom content type (default: “application/xml”)
Struct Tag: xml:"field_name"
Form URL-Encoded Decoder
Parse form-encoded request bodies.
func NewFormURL(opts ...FormURLOption) *FormURL
Options:
WithContentType[T](contentType string)
- Custom content typeWithSplitSymbol(symbol string)
- Set symbol for array splitting
Struct Tag: form:"field_name"
Multipart Form Data Decoder
Parse multipart form data (including file uploads).
func NewMultipartFormData(opts ...MultipartFormDataOption) *MultipartFormData
Options:
WithContentType[T](contentType string)
- Custom content typeWithMaxMemory(maxMemory int64)
- Max memory for file parsing (default: 32MB)
Struct Tag: multipart:"field_name"
Special Types:
*MultipartFile
- Single uploaded fileMultipartFiles
- Multiple uploaded filesmultipart:",allfiles"
- Get all uploaded files
Example:
type FileUploadRequest struct {
Title string `multipart:"title"`
File *decoder.MultipartFile `multipart:"file"`
AllFiles decoder.MultipartFiles `multipart:",allfiles"`
}
Formatters
Formatters post-process parsed values.
String Formatter
Format string values.
func NewString() *String
Struct Tag: string:"operation1,operation2"
Operations:
trim_space
- Remove leading and trailing whitespacelower
- Convert to lowercaseupper
- Convert to uppercasetitle
- Convert to title case (capitalize first letter of each word)snake
- Convert to snake_case formatcamel
- Convert to camelCase formatkebab
- Convert to kebab-case formatslug
- Convert to URL-friendly slug (lowercase with hyphens)base64_encode
- Encode string to base64base64_decode
- Decode base64 stringurl_encode
- URL encode stringurl_decode
- URL decode stringsanitize_html
- Basic HTML sanitization (escape < and >)reverse
- Reverse string characterstrim_prefix=PREFIX
- Remove specified prefix from stringtrim_suffix=SUFFIX
- Remove specified suffix from stringtruncate=N
- Truncate string to N charactersreplace=OLD:NEW
orreplace=OLD:NEW:COUNT
- Replace occurrences of OLD with NEWsubstring=START
orsubstring=START:END
- Extract substringpad_left=LENGTH
orpad_left=LENGTH:CHAR
- Pad string on the leftpad_right=LENGTH
orpad_right=LENGTH:CHAR
- Pad string on the right
Example:
type Request struct {
Name string `json:"name" string:"trim_space,title_case"`
Username string `json:"username" string:"trim_space,lower,slug"`
}
Numeric Formatter
Apply constraints and transformations to numeric values.
func NewNumeric() *Numeric
Struct Tag: numeric:"constraint1,constraint2"
Constraints:
min=N
- Enforce minimum valuemax=N
- Enforce maximum valueabs
- Convert to absolute valueround
- Round to nearest integer (floats only)ceil
- Round up (floats only)floor
- Round down (floats only)
Example:
type Request struct {
Price float64 `json:"price" numeric:"min=0,max=1000"`
Quantity int `json:"quantity" numeric:"min=1,abs"`
Rating float64 `json:"rating" numeric:"min=0,max=5,round"`
}
Time Formatter
Format and manipulate time values.
func NewTime() *Time
Struct Tag: time:"operation1,operation2"
Operations:
timezone=TZ
- Convert to specified timezone (e.g.,UTC
,America/New_York
)truncate=UNIT
- Truncate to unit (hour
,minute
,second
, or duration)start_of_day
- Set to beginning of day (00:00:00)end_of_day
- Set to end of day (23:59:59.999999999)
Example:
type Request struct {
StartTime time.Time `json:"start_time" time:"timezone=UTC,truncate=hour"`
Date time.Time `query:"date" time:"start_of_day"`
Deadline time.Time `json:"deadline" time:"end_of_day"`
}
Slice Formatter
Format and manipulate slice values.
func NewSlice() *Slice
Struct Tag: slice:"operation1,operation2"
Operations:
unique
- Remove duplicate valuessort
- Sort in ascending ordersort_desc
- Sort in descending ordercompact
- Remove zero/empty valueslimit=N
- Limit to first N elements
Example:
type Request struct {
Tags []string `query:"tags" slice:"unique,sort"`
Categories []string `json:"categories" slice:"compact,limit=10"`
Scores []float64 `json:"scores" slice:"sort_desc,limit=5"`
}
Middleware
Type-Safe Middleware
func Middleware[T any](roamer *Roamer) func(http.Handler) http.Handler
Create middleware that parses requests and stores results in context.
Usage:
http.Handle("/endpoint",
roamer.Middleware[RequestStruct](r)(http.HandlerFunc(handler)))
Accessing parsed data:
func handler(w http.ResponseWriter, req *http.Request) {
var data RequestStruct
if err := roamer.ParsedDataFromContext(req.Context(), &data); err != nil {
// Handle error
}
// Use parsed data
}
Struct Tags
Common Tags
Tag | Description | Example |
---|---|---|
json:"field" |
Parse from JSON body | json:"name" |
query:"param" |
Parse from query parameter | query:"page" |
header:"Header-Name" |
Parse from HTTP header | header:"User-Agent" |
cookie:"name" |
Parse from cookie | cookie:"session_id" |
path:"param" |
Parse from path variable | path:"id" |
form:"field" |
Parse from form data | form:"email" |
multipart:"field" |
Parse from multipart data | multipart:"file" |
xml:"field" |
Parse from XML body | xml:"username" |
Default Values
type Request struct {
Page int `query:"page" default:"1"`
PerPage int `query:"per_page" default:"20"`
Sort string `query:"sort" default:"asc"`
}
The default
tag provides fallback values when no data is found.
Multiple Formatters
You can apply multiple formatters to the same field:
type Request struct {
Tags []string `query:"tags" slice:"unique,sort" string:"trim_space,lower"`
}
Formatters are applied in the order they’re registered with Roamer.
Error Handling
Common Errors
NotSupported
- Type conversion not supportedFormatterNotFound
- Unknown formatter requested- Standard parsing errors for malformed data
Error Context
Errors are wrapped with context information to help with debugging:
if err := r.Parse(req, &data); err != nil {
log.Printf("Parsing failed: %+v", err) // Includes stack trace
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
Type Support
Supported Types
Roamer supports automatic conversion to these Go types:
Basic Types:
string
bool
int
,int8
,int16
,int32
,int64
uint
,uint8
,uint16
,uint32
,uint64
float32
,float64
Time:
time.Time
- Supports multiple formats (RFC3339, RFC1123, “2006-01-02”, etc.)
Slices:
[]string
,[]int
,[]float64
, etc.- Automatic splitting on comma (configurable)
Pointers:
- All basic types as pointers (
*string
,*int
, etc.)
Custom Types:
- Types with custom
UnmarshalText
methods - Enums and custom string types
Type Conversion Examples
type Request struct {
// String to int
Age int `query:"age"`
// String to bool (accepts: true/false, 1/0, yes/no)
Active bool `query:"active"`
// String to time.Time
CreatedAt time.Time `query:"created_at"`
// Comma-separated to slice
Tags []string `query:"tags"`
// Optional values
OptionalEmail *string `json:"email"`
}
Performance Considerations
Best Practices
- Use specific request structs - Only include fields needed for each endpoint
- Cache roamer instances - Reuse instances across requests for better performance
- Consider reflection overhead - Roamer uses reflection for struct analysis
Memory Usage
- Roamer uses
sync.Pool
for object reuse where possible - Path parser is the only component that uses caching
- Memory allocations are minimized in parsing hot paths
Benchmarking
For performance-critical applications, benchmark your specific use cases:
func BenchmarkRoamerParse(b *testing.B) {
r := roamer.NewRoamer(/* configure */)
req := /* create test request */
b.ResetTimer()
for i := 0; i < b.N; i++ {
var data RequestStruct
if err := r.Parse(req, &data); err != nil {
b.Fatal(err)
}
}
}