json encode in golang fabric chaincode behavior - go

I've seen several articles with similar errors, but none seems to work for me. I've seen the marbles samples, as well as many others, and still can't pinpoint the error.
I'm in fabric 2.x. The chaincode below works just fine when saving data, but fails when reading with the following message:
ERROR] Error submitting transaction: No valid responses from any peers. Errors:
peer=org1peer-api.127-0-0-1.nip.io:8080, status=500, message=Error handling success response. Value did not match schema:
1. return: Additional property field1 is not allowed
2. return: Additional property field2 is not allowed
3. return: field1,omitempty is required
4. return: field2,omitempty is required
type Asset struct {
Field1 string `json:"field1,omitempty"`
Field2 string `json:"field2,omitempty"`
}
func (c *AssetContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetID string, values string) (bool, error) {
// convert json input to byte array
txData := []byte(values)
// convert byte array to HlpAsset struct
asset := new(asset)
err = json.Unmarshal(txData, &asset)
// convert struct back to bytes
txBytes, err := json.Marshal(asset)
return true, ctx.GetStub().PutState(assetID, txBytes)
}
func (c *AssetContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) {
txBytes, _ := ctx.GetStub().GetState(assetID)
// convert byte array to HlpAsset struct
asset := new(Asset)
err = json.Unmarshal(txBytes, &asset)
return asset, nil
}
testing with the following input data:
assetID: "3",
values: "{\"field1\":\"123\",\"field2\":\"a05\"}"
In addition, I'm not exactly sure why I need to Unmarshal/Marshal. Couldn't I just convert the stringified JSON to byte and save that? I know that works, is it "only" for data validation purposes that this is required?
Anyway, thanks a bunch.

In omitempty fields, set also metadata:",optional" to pass validation. And you cannot set json:"omitempty" metadata:",optional" on all fields of your model. The default Fabric 2.X Go chaincode's transaction serializer does not like it for any reason. If you really need omitempty for those fields, you can add any other dumb field.
You can add a dumb boolean...
type Asset struct {
Dumb bool `json:"dumb"`
Field1 string `json:"field1,omitempty" metadata:",optional"`
Field2 string `json:"field2,omitempty" metadata:",optional"`
}
...or add the key/ID itself to the model...
type Asset struct {
ID string `json:"id"`
Field1 string `json:"field1,omitempty" metadata:",optional"`
Field2 string `json:"field2,omitempty" metadata:",optional"`
}
...or a document type...
type Asset struct {
DocType string `json:"docType"`
Field1 string `json:"field1,omitempty" metadata:",optional"`
Field2 string `json:"field2,omitempty" metadata:",optional"`
}
As an alternative, you can try to override default ContractChaincode's TransactionSerializer (https://pkg.go.dev/github.com/hyperledger/fabric-contract-api-go/contractapi#ContractChaincode). I've done it when migrating a chaincode that already had its own input validation from 1.X to 2.X, to avoid metadata checks and to return seralization errors in my own format; and may work for your case.
Or you can return a string instead of an *Asset from ReadAsset as a workaround to avoid the check that is causing your error, so that it is deserialized only in the client. In fact, I find not much coherent to receive an string in CreateAsset, but return an *Asset in ReadAsset. I would use the same format for both (*Asset, preferably, unless you are stuck with your issue).

I found this question where this bug is mentioned:
Supplying additional valid data in JSON tag of struct property causes schema to fail.
The bug has been closed for around a year, however, I still experience that behavior. Overriding the JSON property using medatada didn't work either.
Using the struct like this worked perfectly:
type Asset struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
}

Related

Reflection to get field tag

In Go is there a good way to use reflection to get a field tag by just wrapping a field in a function from the reflect library?
I am basically trying to create a thin data access object that allows be to get the column name in the db without hard coding it all over the place.
Below is the struct with db column names as tags.
// Table Structures
type CusipTableRow struct {
Id int64 `db:"id"`
Cusip string `db:"cusip"`
Symbol string `db:"symbol"`
Active int8 `db:"active"`
Added_Time int32 `db:"added_timestamp"`
Description string `db:"description"`
Exchange string `db:"exchange"`
AssetType string `db:"asset_type"`
}
I am seeking a suggestion other than downloading another library on how to use reflection to essentially make a call like this to return a string with the tag value.
var row CusipTableRow
row.GetColumnName(row.Id) //Return column name based on tag.
I was considering possibly trying to use a map[address] fieldTag, but did not have luck getting that to work perhaps due to not fully having a grasp of the unsafe package. If that approach would have worked I was thinking a call like this could have worked:
row.GetColumnName(&row.Id) //Return column name based on tag.
You can get field tag given the address of the struct and the address of the field. Unsafe shenanigans are not required.
func GetColumnName(pstruct interface{}, pfield interface{}) string {
v := reflect.ValueOf(pstruct).Elem()
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Addr().Interface() == pfield {
return v.Type().Field(i).Tag.Get("db")
}
}
panic("field not in struct")
}
Example use:
var v CusipTableRow
fmt.Println(GetColumnName(&v, &v.Added_Time)) // prints added_timestamp
Run it on the Go Playground.

Go build with protocol buffer error: too few values in struct initializer

I have a proto file:
syntax = "proto3";
package main;
message Client {
int32 Id = 1;
string Name = 2;
string Email = 3;
}
The compiled Client struct like below:
type Client struct {
Id int32 `protobuf:"varint,1,opt,name=Id,proto3" json:"Id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
Email string `protobuf:"bytes,3,opt,name=Email,proto3" json:"Email,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
When I am trying to init this Client struct like below:
client := &Client{123, "John", "john#aol.com"}
I am getting building error: too few values in struct initializer. I found a way to fix it by adding XXX_NoUnkeyedLiteral, XXX_unrecognized, XXX_sizecache. I don't know what these are, and wondering if this is the right way to do it:
client := &Client{123, "John", "john#aol.com", struct{}{}, []byte{}, int32(0)}
In struct composite literals you may omit the field names to which you list values for (this is called unkeyed literal), but then you have to list initial values for all fields and in their declaration order. Or you may use a keyed literal where you explicitly state which fields you specify initial values for. In the latter, you are allowed to omit any of the fields, you may just list the ones you want to give an initial value different from the field's zero value).
You used unkeyed composite literal, in which case you must list values for all fields, which you didn't. This is what the error message tells you: "too few values in struct initializer".
The field name (generated by protobuf) itself should give you the hint: XXX_NoUnkeyedLiteral. It suggests you should not use a composite literal without keys.
So use a composite literal with keys, like this::
client := &Client{
Id: 123,
Name: "John",
Email: "john#aol.com",
}
This form is more readable, and it is immune to struct changes. E.g. if the Client struct would get new fields, or fields would get rearranged, this code would still be valid and compile.
Add field name before the value can solve the building error, as
client := &Client{Id: 123, Name: "John", Email: "john#aol.com"}
I find this out by checking the grpc golang example, but maybe somebody can explain why? ;)

Unmarshal json without elements names

I´m trying to read a json file and parse into jsonObject in my Go class.
The json has a random names and number of elements when I receive it.
For example:
{"707514313":1505680270,"1568212945":1505676950,"732898933":1505681884}
So all the examples that I´ve seen that use an struct to define the interface for the unmarshal, where they put the names of the json values, but in my case I cannot do it since I dont know how many and the name of the values of the json.
var settings struct {
Name1 string `json:"707514313"`
Name2 string `json:"1568212945"`
Who knows how many more and with which names?!
}
So I end up unmarshalling with the default interface
func loadFileToJson(filename string) {
plan, _ := ioutil.ReadFile(filename)
var data interface{}
checkError(json.Unmarshal(plan, &data))
fmt.Println("Data %s ", data)
}
That load in data a (map[String]interface{})
Any idea how to achieve what I want.
EDIT:
I create this struct
type Structure struct {
Name map[string]uint64
}
And changing the old default by
var jsonObject []Structure
checkError(json.Unmarshal(plan, &jsonObject))
Is giving me this error
json: cannot unmarshal object into Go value of type []main.StructureData %s []
As #Anzel pointed out your data appears to be perfect for a map[string]uint64. This assumes a couple things, namely that your object keys are always strings (as in your example) and that the values are always uint64 (again as your sample data suggested). As such, unmarshal into that data type instead of interface{}
plan := []byte(`{"707514313":1505680270,"1568212945":1505676950,"732898933":1505681884}`)
var data map[string]uint64
json.Unmarshal(plan, &data)
fmt.Printf("Data is %+v\n", data)
OUTPUT
Data is map[1568212945:1505676950 732898933:1505681884 707514313:1505680270]
As commented, you just need to set the field type as map[string]uint64 and implement a few methods to parse the file and get the map value.
See in this playground for some pseudo code:
playground
However, depending on your map values, you may need to define the field type as map[string]uint64 or whatever reflecting the json structure, e.g. map[string]interface{} or even a separate embedded struct with nested structure.
Hope this helps.

Check if any field of struct is nil

If there any clean way to check if any field value of struct is nil?
Suppose i have
type test_struct struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required"`
Message string `json:"message" binding:"required"`
}
And with Gin i am filling the struct with values as
var temp test_struct
c.Bind(&temp)
And everything works fine, but i want to check if any of temp.Name, temp.Email, temp.Message is nil, sure we can check it by simply comparing each field with nil: if temp.Name == nil and so on, but i am looking for a cleaner version of that, is there any?
UPD: Due to a lack of knowledge in Go language i didn't know that the Bind function of gin package return an error if we pass a strucure with binding:"required" fields. Thanks to #matt.s i get it. So the answer would be to check the err:
var temp test_struct
err := c.Bind(&temp)
if err != nil {
// Do my stuff(some of fields are not set)
}
You should first check that Bind doesn't return an error. If it doesn't then all fields will be set to their appropriate values or initialized to zero values if not. This means that the strings are guaranteed to not be nil (though they will be set to "" if they did not have a value).

golang - Rest update request using http patch semantics

type A struct {
Id int64
Email sql.NullString
Phone sql.NullString
}
Assume I have one record in the database
A{1, "x#x.com", "1112223333"}
Send an update request via PUT
curl -X PUT -d '{"Email": "y#y.com", "Phone": null}' http://localhost:3000/a/1
Here is the psuedo algorithm that would work with a full PUT request (i.e. update all fields of the record A - but it will cause difficulties with the PATCH request semantics - delta update)
-- Unmarshal json into empty record
a := A{}
json.Unmarshal([]byte(request.body), &a)
-- Load the record from the database
aFromDb = <assume we got record from db> //A{1, "x#x.com", "1112223333"}
-- Compare a and aFromDB
-- Notice the email change and set it on aFromDb - ok
-- Notice the phone number change -- but wait! Was it set to NULL in the JSON explicitly or was it not even included in the JSON? i.e. was the json request - {"Email": "y#y.com", "Phone": null} or was it {"Email": "y#y.com"}?
How can we tell by just looking at the unmarshaled json into the struct a?
Is there another method to do the update via rest (with patch semantics)? I am looking for a generic way to do it (not tied to a particular struct).
I created a separate datatype for this purpose. This example is for an int64 (actually string-encoded int64), but you can easily change it to a string as well. The idea behind it is, that the UnmarshalJSON method will only be called if the value is present in the JSON. The type will implement the Marshaler and the Unmarshaler.
// Used as a JSON type
//
// The Set flag indicates whether an unmarshaling actually happened on the type
type RequiredInt64 struct {
Set bool
Int64 int64
}
func (r RequiredInt64) MarshalJSON() ([]byte, error) {
lit := strconv.FormatInt(r.Int64, 10)
return json.Marshal(lit)
}
func (r *RequiredInt64) UnmarshalJSON(raw []byte) error {
var lit string
var err error
if err = json.Unmarshal(raw, &lit); err != nil {
return err
}
r.Int64, err = strconv.ParseInt(lit, 10, 64)
if err != nil {
return err
}
r.Set = true
return nil
}
So, if Set is false, you know that the value was not present in the JSON.
Try adding this tags to the struct:
type A struct {
Id int64 `json:"Id,omitempty"`
Email sql.NullString `json:"Email,omitempty"`
Phone sql.NullString `json:"Phone,omitempty"`
}
In this way if you are serializing and the field is empty then the json will not contain the field.
When deserializing though the field will have a either a value or it will have the default value for the type (Nil for the pointer or empty string for strings).
You could potentially write your own marshalling/uinmarshalling of your struct and react to the raw response within, although it might be non-obvious witgh inspection what that those functions are manipulating.
Alternatively, you could not omitempty within your fields and force null populated fields.
Or, maybe leveraging a different flavor of patching, perhaps http://jsonpatch.com/, which is more explicit in the nature of your modifications. This would require the client to be more understanding of the state of changes than say for a put.

Resources