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
I'm having trouble using binary parameters, I'm not sure what I'm doing wrong.
I have a parameter defined with:
"note-prefix": {
"type": "string",
"format": "byte",
"description": "Specifies a prefix which must be contained in the note field.",
"name": "note-prefix",
"in": "query"
},
This generates a parameter object as expected with:
NotePrefix *[]byte `json:"note-prefix,omitempty"`
Now I try to use the parameter by getting a base64 string echo "test" |base64, and url encoding it to get dGVzdAo%3D.
But the parameter isn't properly parsed:
$ curl -s "localhost:8980/transactions?note-prefix=dGVzdAo%3D" | json_pp
{
"message" : "Invalid format for parameter note-prefix: error setting array element: error binding string parameter: can not bind to destination of type: uint8"
}
This seems to be a problem with BindQueryParameter for optional parameters, and I was able to detect the byte array type inside the IsNil check. But I wasn't sure how to turn this knowledge into a working version of BindQueryParameter.
} else {
// For optional parameters, we have an extra indirect. An optional
// parameter of type "int" will be *int on the struct. We pass that
// in by pointer, and have **int.
// If the destination, is a nil pointer, we need to allocate it.
if v.IsNil() {
+ switch v.Kind() {+ case reflect.Slice:+ if v.Type() == reflect.TypeOf([]byte(nil)) {+ fmt.Println("byte array parameter detected")+ }+ }
t := v.Type()
newValue := reflect.New(t.Elem())
// for now, hang onto the output buffer separately from destination,
// as we don't want to write anything to destination until we can
// unmarshal successfully, and check whether a field is required.
output = newValue.Interface()
} else {
// If the destination isn't nil, just use that.
output = v.Interface()
}
// Get rid of that extra indirect as compared to the required case,
// so the code below doesn't have to care.
v = reflect.Indirect(reflect.ValueOf(output))
}
The issue seems to be that BindQueryParameter assumes that if the destination is a slice it's the target for individual query parameters, which is not the case for format byte which is expecting a single parameter stored. Unfortunately even with explode: false it still calls bindSplitPartsToDestinationArray which doesn't handle this case.
We could update BindQueryParameter to treat a slice of uint8 aka byte as a special case, but not sure if that's backwards compatible.
Runtime fix is up in #98. The code generator still needs to be updated to emit calls to the new WithOptions functions with TypeHintBinary — tracked in oapi-codegen/oapi-codegen#2248.
This is now fixed in the runtime and released as v1.2.0. This PR in the main codegen incorporates these changes, and I've verified that binary parameters marshal correctly: oapi-codegen/oapi-codegen#2256
Activity
winder commentedon Apr 21, 2020
This seems to be a problem with
BindQueryParameterfor optional parameters, and I was able to detect the byte array type inside theIsNilcheck. But I wasn't sure how to turn this knowledge into a working version ofBindQueryParameter.} else { // For optional parameters, we have an extra indirect. An optional // parameter of type "int" will be *int on the struct. We pass that // in by pointer, and have **int. // If the destination, is a nil pointer, we need to allocate it. if v.IsNil() { + switch v.Kind() { + case reflect.Slice: + if v.Type() == reflect.TypeOf([]byte(nil)) { + fmt.Println("byte array parameter detected") + } + } t := v.Type() newValue := reflect.New(t.Elem()) // for now, hang onto the output buffer separately from destination, // as we don't want to write anything to destination until we can // unmarshal successfully, and check whether a field is required. output = newValue.Interface() } else { // If the destination isn't nil, just use that. output = v.Interface() } // Get rid of that extra indirect as compared to the required case, // so the code below doesn't have to care. v = reflect.Indirect(reflect.ValueOf(output)) }stevenh commentedon Mar 9, 2024
The issue seems to be that
BindQueryParameterassumes that if the destination is a slice it's the target for individual query parameters, which is not the case for formatbytewhich is expecting a single parameter stored. Unfortunately even withexplode: falseit still callsbindSplitPartsToDestinationArraywhich doesn't handle this case.We could update
BindQueryParameterto treat a slice of uint8 aka byte as a special case, but not sure if that's backwards compatible.fix: add TypeHint-aware parameter binding and styling for []byte (oap…
mromaszewicz commentedon Feb 25, 2026
Runtime fix is up in #98. The code generator still needs to be updated to emit calls to the new
WithOptionsfunctions withTypeHintBinary— tracked in oapi-codegen/oapi-codegen#2248.fix: add Type/Format-aware parameter binding and styling for []byte (o…
fix: add Type/Format-aware parameter binding and styling for []byte (#97
mromaszewicz commentedon Feb 26, 2026
This is now fixed in the runtime and released as v1.2.0. This PR in the main codegen incorporates these changes, and I've verified that binary parameters marshal correctly:
oapi-codegen/oapi-codegen#2256