Skip to content

Repository files navigation

Value Extractor

GitHub go.mod Go versionGo Report CardGitHub licenseGitHub starsGitHub forksGo Reference

This package provides a flexible system for extracting values from various sources (like HTTP requests, maps, etc.) and converting them into the desired Go types with comprehensive error handling. It's designed to make it easier to work with dynamic data sources in a type-safe manner.

Features

  • Extensible Value Extraction: Supports extracting values from maps, HTTP request query parameters, and form data.
  • Type Conversion: Convert extracted strings into specific Go types (string, uint64, int64, float64, bool), including custom type conversions.
  • Direct Return Types: Provides direct return functions (ReturnString, ReturnUint64, etc.) for performance optimization.
  • Error Handling: Collects and aggregates errors throughout the extraction and conversion process for robust error reporting.
  • No external dependencies - only the Go standard library.
  • Fast - run go test -bench .. It's between 20-40% faster than the idiomatic struct tag + reflection.
  • Lighweight - Less than 300 LOC.
  • Easy to read - Only 1 if err != nil for all of your conversions.

Getting Started

Installation

go get github.com/Howard3/valueextractor

Basic Usage

Here are quick examples to get you started:

There are three main ways to use this library:

  • References
  • Direct value return objects
  • Return Generics

Using References

package main
import (
"fmt""net/http""github.com/Howard3/valueextractor"
)
funcmain() {
// Initialize the extractor with optional keys using the new fluent interfacereq, _:=http.NewRequest("GET", "/?id=123&name=John&age=30", nil)
ex:=valueextractor.Using(valueextractor.QueryExtractor{Query: req.URL.Query()}, valueextractor.WithOptionalKeys("age", "foo"))
variduint64varnamestringvarageuint64// Note: 'age' is treated as an optional parameterex.With("id", valueextractor.AsUint64(&id))
ex.With("name", valueextractor.AsString(&name))
ex.With("age", valueextractor.AsUint64(&age)) // No error if 'age' is missingiferr:=ex.Errors(); err!=nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("Extracted values - ID: %d, Name: %s, Age: %d\n", id, name, age)
}
}

Fluent Initialization with Optional Keys

The Using function supports a fluent interface for specifying optional keys. This is achieved using the WithOptionalKeys function, which modifies the extractor's behavior to treat certain keys as optional during value extraction. If these keys are missing from the source, their absence will not contribute to the error collection, simplifying error handling for optional data.

ex:=valueextractor.Using(QueryExtractor{Query: req.URL.Query()}, valueextractor.WithOptionalKeys("age", "foo"))

This approach allows you to declaratively specify which keys are optional, enhancing code readability and reducing the boilerplate associated with optional value handling.

Using Direct Return Functions

package main
import (
"fmt""github.com/Howard3/valueextractor"
)
funcmain() {
ex:= valueextractor.NewExtractor(...) // Assume ex is properly initializedif*valueextractor.ReturnString(ex, "name") !="John" {
fmt.Println("Name not parsed correctly")
}
if*valueextractor.ReturnUint64(ex, "age") !=30 {
fmt.Println("Age not parsed correctly")
}
}

Using Return Generics

Return generics are easy to work with but have approximately the same performance as the struct+reflection approach.

package main
import (
"fmt""net/http""github.com/Howard3/valueextractor"
)
funcmain() {
// Example: Extracting values from a query parameterreq, _:=http.NewRequest("GET", "/?id=123&name=John", nil)
queryExtractor:= valueextractor.QueryExtractor{Query: req.URL.Query()}
ex:=valueextractor.Using(queryExtractor)
id:=valueextractor.Result(ex, "id", valueextractor.AsUint64)
name:=valueextractor.Result(ex, "name", valueextractor.AsString)
iferr:=ex.Errors(); err!=nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("Extracted values - ID: %d, Name: %s\n", id, name)
}
}

Extensibility

The system is designed with extensibility in mind. You can extend it by implementing custom ValueExtractor interfaces or Converter functions. See the documentation for details on creating custom extractors and converters.

Implementing a Custom ValueExtractor

To extract values from a new data source, implement the ValueExtractor interface:

typeCustomExtractorstruct {}
func (ceCustomExtractor) Get(keystring) (string, error) {
// Logic to extract and return the value based on the key
}

Adding a New Converter Function

To support converting to a new type:

funcAsCustomType(ref*CustomType) valueextractor.Converter {
returnfunc(ec*valueextractor.Extractor, valuestring) error {
// Convert value to CustomType and assign to ref*ref=newVal// assign the new valuereturnnil
}
}

Error Handling

Errors are collected throughout the extraction and conversion process. Use the Errors method to retrieve any accumulated errors. The package defines ErrNotFound for missing keys and provides detailed error types for extract and convert errors, allowing precise error handling and diagnostics.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

This package provides a flexible system for extracting values from various sources (like HTTP requests, maps, etc.) and converting them into the desired Go types with comprehensive error handling. It's designed to make it easier to work with dynamic data sources in a type-safe manner.

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages