on
adding default values to github.com/gorilla/schema
Around July 2021, I made a proposal to add a new functionality to github.com/gorilla/schema library: the possiblity to set default values when the target struct field value is nil or is not set. For those who don’t know, schema library is a dead simple util library that gives you the ability to encode/decode anything of type url.Values
to/from a golang struct, in the same spirit as the well famous github.com/mitchellh/mapstructure. The library was created mainly to be used for form values, but it can be used with query parameters because both use the type url.Values
. schema
works only with map[string][]string
(which is the alias type for url.Values
), while mapstructure
has no requirements on the target/source type when decoding encoding (which makes it more popular).
The proposal to add a default tag option:
For my pet project imager200.io, the API relies primarily on query parameters because the request body is used in most endpoints for sending over image bytes. To handle a large number of query parameters more intuitively, I started to work with github.com/gorilla/schema library. I quickly realized that I needed a bit more that just decoding query parameters into structs. Having to check every struct field and setting defaults is not only repetitive and somehow not faitful to the DRY concept, but also makes looking for those values tedious when documenting the defaults for each endpoint parameters. I had the idea of making the schema
do this when doing the decoding, since schema
has to go through each struct field anyway. The initial proposal was as follows:
type Person struct {
Name string `schema:"name,required"`
Phone string `schema:"phone" schemaDefault:"+1234567890"`
}
Whenever schemaDefault
is provided, schema
should set the default value for the field in question. Additionally, I made the assumption that any required field should not have a default, and adding the default tag for a field that has the required
option should make the decoding fail. The initial work on this functionality can be found in this commit: https://github.com/gorilla/schema/pull/183/commits/12fe3557332a9e8b6f3222115ca27fdd3da97da6
After some discussion with the community (more details in the issue: https://github.com/gorilla/schema/issues/182), we came to the conclusion that a separate tag is unecessary, because it’s a good practice to have a package expose one tag only (there are projects that do not adhere to this rule, e.g the famous https://github.com/caarlos0/env). Accordingly, the initial proposal was altered so that the default can be provided as a tag option rather than a standalone tag:
type Person struct {
Name string `schema:"name,required"`
Phone string `schema:"phone,default=+1234567890"`
}
The implementation can be found in the PR: https://github.com/gorilla/schema/pull/183
The decision to archive the schema project:
Unfortunately, the Gorilla organization, which is behind schema
and many useful Golang projects like Mux and Websocket, announced that it was shutting down because the creators were not able to keep up with maintainance which requires considerable time and effort. There was an initial attempt to find maintainers, but at the end, the team found it difficult to just give away the projects to random people (even with proven track record on Github):
Since the attempt to find maintainers failed, all the Gorilla projects were officially archived by the end of 2022.
It was sad to see, but my effort to add the default functionality was still worth it, because I could use it from my own fork.
The Gorilla organization was rescued by Red Hat:
Around July 2023, an annoucement was made that the Gorilla organization is coming out of the closet again: https://gorilla.github.io/blog/2023-07-17-project-status-update/
According to the annoucement:
To address many comments that we have seen - we would like to clarify that Red Hat is not taking over this project. While the new Core Maintainers all happen to work at Red Hat, our hope is that developers from many different organizations and backgrounds will join the project over time.
In other words, Red Hat is somehow sponsoring the organization by having some of their engineers spend a portion of their time maintaining the projects. Based on the amount of activity seen so far, it seems like maintaining the Gorilla projects is not the core activity of the new maintainers, but anyway, it’s good news and a win for open source knowing that projects like mux (~20K stars) and websocket (~21k stars) are still used extensively in code bases.
The PR was finally reviewed and merged to upstream:
To my surprise, the PR was considered again, and after few follow up commits, it was merged to upstream. The default functionality is now officially part of the gorilla schema v1.3.0 release.
Example usage:
import (
"fmt"
"net/url"
"github.com/gorilla/schema"
)
type Parameters struct {
Offset int `schema:"offset,default:20"`
Size int `schema:"size,default:25"`
Details bool `schema:"details,default:true"`
}
var decoder = schema.NewDecoder()
func main() {
var parameters Parameters
// giving empty url.Values for demonstration purposes
err := decoder.Decode(¶meters, url.Values{})
if err != nil {
// Handle error
}
fmt.Printf("%v", parameters)
//result: {20 25 true}
}