You signed in with another tab or window.Reload to refresh your session.You signed out in another tab or window.Reload to refresh your session.You switched accounts on another tab or window.Reload to refresh your session.Dismiss alert
qparser is a lightweight Go package designed to parse URL query parameters directly into Go structs. It is built on the Go standard library, offering a simple and focused solution for handling incoming query strings.
Here's an example of how to useqparser to parse query parameters into struct fromnet/http request.
// Representing basic pagination, /path?page=1&limit=5typePaginationstruct {Pageint`qp:"page"`Limitint`qp:"limit"`}funcMyHandler(w http.ResponseWriter,r*http.Request) {varpaginationPaginationerr:=qparser.ParseRequest(r,&pagination)iferr!=nil {// Handle Error }// Do something with pagination}
Parse from URL
You can also parse query parameters from URL string by calling theParseURL function. Here's an example:
funcmain() {varpaginationPaginationurl:="http://example.com/path?page=1&limit=5"err:=qparser.ParseURL(url,&pagination)iferr!=nil {// Handle Error }// Do something with pagination}
Parse from url.Values
You can also parse query parameters directly fromurl.Values by calling theParse function. Here's an example:
funcmain() {varpaginationPaginationvalues:= url.Values{"page": []string{"1"},"limit": []string{"5"}, }err:=qparser.Parse(values,&pagination)iferr!=nil {// Handle Error }// Do something with pagination}
Multiple Values Query & Nested Struct
To support multiple values for a single query parameter, use a slice type. For nested structs, utilize the qp tag within the fields of the nested struct to pass the query parameters. It's important to note that the parent struct containing the nested/child structshould not have its own qp tag. Here's an example:
// Representing filter for menutypeMenuFilterstruct {Categories []string`qp:"categories"`Availablebool`qp:"available"`}typePaginationstruct {Pageint`qp:"page"`Limitint`qp:"limit"`}typeMenuQueryParamsstruct {FilterMenuFilterPaginationPagination}funcGetMenus(w http.ResponseWriter,r*http.Request) {varfMenuQueryParamsiferr:=qparser.ParseRequest(r,&f);err!=nil {// Handle Error }// Do something with f.Filter and f.Pagination}
There are three ways for the parser to handle multiple values query parameters:
Simply ensure that the qp tags are defined appropriately in your struct fields to map these parameters correctly.
Time Handling
Supports time.Time, *time.Time, and type aliases. Handles a variety of standard time formats, both with and without timezone offsets, and supports nanosecond-level precision. Date formats follow the YYYY-MM-DD layout.
Format Description
Layout Example
RFC3339 (Z or offset)
2006-01-02T15:04:05Z07:00
RFC3339Nano (Z or offset, nanosecond prec)
2006-01-02T15:04:05.999999999Z07:00
Time only
15:04:05
Date only
2006-01-02
Date & time (space separated)
2006-01-02 15:04:05
Date & time + milliseconds
2006-01-02T15:04:05.000
Date & time + microseconds
2006-01-02T15:04:05.000000
Date & time + nanoseconds
2006-01-02T15:04:05.999999999
Date & time + TZ offset
2006-01-02T15:04:05-07:00
Date & time + milliseconds + TZ
2006-01-02T15:04:05.000-07:00
Date & time + microseconds + TZ
2006-01-02T15:04:05.000000-07:00
Date & time + nanoseconds + TZ
2006-01-02T15:04:05.999999999-07:00
Space separator + TZ
2006-01-02 15:04:05-07:00
Space separator + TZ (+ offset)
2006-01-02 15:04:05+07:00
Space separator + fractional + TZ
2006-01-02 15:04:05.123456789-07:00
Fractional seconds (milliseconds, microseconds, nanoseconds) are supported with or without a timezone.
Timezones may use Z, +HH:MM, or -HH:MM.
No support for named timezones (e.g., PST, UTC)—only numeric offsets.
Example:
typeReportFilterstruct {From time.Time`qp:"from"`To time.Time`qp:"to"`}funcmain() {varfilterReportFilterurl:="http://example.com/reports?from=2025-07-01&to=2025-07-31"err:=qparser.ParseURL(url,&filter)iferr!=nil {// Handle Error }// Do something with filter}
Supported field types
String
Boolean
Integers (int, int8, int16, int32 and int64)
Unsigned Integers (uint, uint8, uint16, uint32 and uint64)
Floats (float64 and float32)
Slice of above types
Nested Struct
time.Time
A pointer to one of above
Error Handling
qparser provides detailed error information with field-specific context. Errors are wrapped with field names to help identify exactly which parameter failed to parse.
typeUserFilterstruct {Ageint`qp:"age"`Activebool`qp:"active"`Namestring`qp:"name"`}funcmain() {varfilterUserFilter// Simulate invalid query parametersvalues:= url.Values{"age": []string{"invalid_age"},// Invalid integer"active": []string{"maybe"},// Invalid boolean"name": []string{"John"},// Valid }err:=qparser.Parse(values,&filter)iferr!=nil {// Check for specific error typesvarfieldErr*qparser.FieldErroriferrors.As(err,&fieldErr) {fmt.Printf("Field error in %q: %v\n",fieldErr.FieldName,fieldErr.Err)// Handle specific error typesswitch {caseerrors.Is(fieldErr.Err,qparser.ErrInvalidValue):fmt.Printf("Invalid value format for field %s\n",fieldErr.FieldName)caseerrors.Is(fieldErr.Err,qparser.ErrOutOfRange):fmt.Printf("Value out of range for field %s\n",fieldErr.FieldName)caseerrors.Is(fieldErr.Err,qparser.ErrUnsupportedKind):fmt.Printf("Unsupported type for field %s\n",fieldErr.FieldName) } }else {fmt.Printf("General error: %v\n",err) }return }fmt.Printf("Parsed filter: %+v\n",filter)}
Error Types
qparser defines several error types for different parsing scenarios:
ErrInvalidValue: Value cannot be parsed as the target type (e.g., "abc" as integer)
ErrOutOfRange: Value is too large for the target numeric type (e.g., "999" as int8)
ErrUnsupportedKind: Target type is not supported by the parser
TheFieldError type provides both the field name and the underlying error:
typeFieldErrorstruct {FieldNamestring// Name of the field that failedErrerror// Underlying error}
This allows you to:
Identify exactly which field failed parsing
Access the specific error type for targeted error handling
Provide user-friendly error messages in your API responses
Notes
Empty query values are not validated by default. For custom validation (including empty value checks), implement your own validation method on the struct or use a third-party validator such as go-playground/validator.
Missing query parameters:
Primitive fields keep their zero values (0, "", false, etc.).
Pointer-to-primitive fields (e.g.,*string,*int) remainnil when the parameter is missing. They are only allocated when the parameter is provided.
Slice fields ([]T) remainnil when the parameter is missing. They are allocated only when at least one value is successfully decoded.
Pointer-to-slice fields (*[]T) remainnil when the parameter is missing. They are allocated only when the parameter is provided.
Pointer-to-struct fields arealways initialized, even when the nested parameters are missing. They contain the zero value of the struct.
For repeated query parameters, the value is appended to the slice every time. If you want deduplication or sanitization, implement a post-processing method on your struct.
Theqp tag is case-sensitive and must match the query parameter key exactly.
Pointer-to-struct fields offer no practical benefit because they are always initialized and nevernil, you cannot rely onnil checks to detect whether a nested parameter group was supplied. If you need that behavior, inspect field values or apply custom post-processing.
Base cost: 1 allocation for parsing infrastructure
Dates: Each successful parse creates exactly 1 allocation
Slices: Each slice parsing creates exactly 2 allocations
Scaling Behavior
Linear growth: Time and memory scale proportionally with item count
Predictable: 2× items = ~2× time, exactly 2× memory
Consistent: Same allocation count regardless of data size
Cache Behavior
First use: Reflection builds struct metadata cache
Subsequent uses: Zero-allocation cache lookups
Thread-safe: sync.Map enables concurrent access
Persistent: Cache lives for application lifetime
Concurrency
Parallel execution leverages sync.Map for effective caching, significantly improving performance under concurrent workloads like HTTP handlers by reducing per-operation time