strategy for REST API in go - database

In my database, each row corresponds to a struct
type datum struct{
Id *string `json:"task_id"`
Status *string `json:"status"`
AccountId *string `json:"account_id"`
.... // many more fields, all of pointer types
}
On the webpage, the user can query on several fields of datum (say account_id and status). The server will return all data that satisfy the query with a projection of the fields (say Id, account_id and status).
Right now, I wrote a HTTP handler to
Extract the query as a datum object from the request:
body, err := ioutil.ReadAll(r.Body)
condition := datum{}
err = json.Unmarshal(body, &condition)
Use the partially filled datum object to query the database, only the non-nil fields translate to SELECT ... WHERE ..=... The query result is saved in query_result []datum
Write the query_result into json object for reply:
reply := map[string]interface{}{
"reply": query_result,
}
data, err := json.Marshal(reply)
The problem is that in the reply many of the fields are nil, but I still send them, which is wasteful. On the other hand, I don't want to change the datum struct to include omitempty tag because in the database a value entry has all fields non-nil.
In this case, shall I define a new struct just for the reply? Is there a way to define this new struct using datum struct, instead of hard code one?
Is there a better design for this query feature?

You have several options, with choice depending what is more wasteful/expensive in your particular case:
Just use pointers+omitempty in the original struct.
Prepare a custom response object. But you'll need to copy/convert the values from the original struct into its export version.
Write a custom marshaller, that will be exploring your struct and creating an export-ready variant, this way being more dynamic/automatic that #1.
While #1 needs no comments, and #2 to some extend covered by Gepser above, here's how you can address this with a custom marshaller (the idea is to re-assemble your output skipping nil fields):
package main
import (
"fmt"
"encoding/json"
"reflect"
)
type datum struct {
Id *string `json:"task_id"`
Status *string `json:"status"`
AccountId *string `json:"account_id"`
}
type Response struct {
Reply []datum `json:"reply"`
}
func main() {
var query_result []datum
// mocking a query result with records with nil fields
val_id_a := "id-a"
val_status := "status-b"
d1 := datum{
Id: &val_id_a,
Status: &val_status,
}
query_result = append(query_result, d1)
val_id_b := "id-b"
val_account_id := "account-id-b"
d2 := datum{
Id: &val_id_b,
AccountId: &val_account_id,
}
query_result = append(query_result, d2)
reply := &Response{
Reply: query_result,
}
data, err := json.Marshal(reply)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", string(data))
}
// MarshalJSON is a custom JSON marshaller implementation for Response object.
func (r *Response) MarshalJSON() ([]byte, error) {
a := struct {
Reply []map[string]interface{} `json:"reply"`
}{}
for _, v := range r.Reply {
a.Reply = append(a.Reply, converter(v))
}
return json.Marshal(a)
}
// converter converts a struct into a map, skipping fields with nil values.
func converter(in interface{}) map[string]interface{} {
out := make(map[string]interface{})
v := reflect.ValueOf(in)
for i := 0; i < v.NumField(); i++ {
f := v.Type().Field(i)
tag := f.Tag.Get("json")
if tag != "" && !v.Field(i).IsNil() {
out[tag] = v.Field(i).Interface()
}
}
return out
}

The approach I suggest (is the one I use) is the new struct with omitempty tag, for example:
type datumResponse struct{
Id *string `json:"task_id,omitempty"`
Status *string `json:"status,omitempty"`
AccountId *string `json:"account_id,omitempty"`
.... // many more fields
}
and there is no option to write your new struct using the fields of the old one if there is not substructs or you don't write an array of structs.

Related

Range over elements of a protobuf array in Go

I have a Protobuf structure defined as so in my .proto file:
message Msg{
message SubMsg {
string SubVariable1 = 1;
int32 SubVariable2 = 2;
...
}
string Variable1 = 1;
repeated SubMsg Variable2 = 2;
...
}
I pull data into this structure using the https://godoc.org/google.golang.org/protobuf/encoding/protojson package when consuming data from a JSON API, as so:
Response, err := Client.Do(Request)
if err != nil {
log.Error(err)
}
DataByte, err := ioutil.ReadAll(Response.Body)
if err != nil {
log.Error(err)
}
DataProto := Msg{}
err = protojson.Unmarshal(DataByte, &DataProto)
if err != nil {
log.Error(err)
}
What I want to be able to do is to range over the elements of Variable2 to be able to access the SubVariables using the protoreflect API, for which I have tried both:
Array := DataProto.GetVariable2()
for i := range Array {
Element := Array[i]
}
and also:
DataProto.GetVariable2().ProtoReflect().Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) {
…
return true})
The first of which fails with error message:
cannot range over DataProto.GetVariable2() (type *SubMsg)
despite the fact DataProto.GetVariable2() returns a variable of type []*Msg_SubMsg.
The second of which fails with:
DataProto.GetVariable2.ProtoReflect undefined (type []*SubMsg has no field or method ProtoReflect)
which suggests that DataProto.GetVariable2() does indeed return an array unlike what is suggested in the error returned in my first approach. This makes sense to me as the protoreflect API only allows this method to be called on a defined message, not an array of those messages. There therefore must be another way of accessing the elements of these arrays to be able to make use of the protoreflect API (for which I have been unsuccessful in finding and answer to on the web thus far).
Could someone help me make sense of these seemingly conflicting error messages? Has anyone had any success iterating over a Protobuf array themselves?
Thanks in advance.
You'll want to treat your Array variable as a List, which means you can't use Range() as in your second attempt. It's close though. Here is a functional example of iterating through and inspecting nested messages:
import (
"testing"
"google.golang.org/protobuf/reflect/protoreflect"
)
func TestVariable2(t *testing.T) {
pb := &Msg{
Variable2: []*Msg_SubMsg{
{
SubVariable1: "string",
SubVariable2: 1,
},
},
}
pbreflect := pb.ProtoReflect()
fd := pbreflect.Descriptor().Fields().ByJSONName("Variable2")
if !fd.IsList() {
t.Fatal("expected a list")
}
l := pbreflect.Get(fd).List()
for i := 0; i < l.Len(); i++ {
// should test that we are now inspecting a message type
li := l.Get(i).Message()
li.Range(func(lifd protoreflect.FieldDescriptor, liv protoreflect.Value) bool {
t.Logf("%v: %v", lifd.Name(), liv)
return true
})
}
}
Run with go test -v ./... if you want to see output

How to make scanning DB rows in Go DRY?

I have a table in the database containing user account information. I have a struct called User defined.
type User struct {
Id uint
Username string
Password string
FirstName string
LastName string
Address1 string
Address2 string
.... a bunch more fields ...
}
For fetching individual user accounts, I have a method defined
func (user *User) GetById(db *sql.DB, id uint) error {
query := `SELECT
...a whole bunch of SQL ...
WHERE id = $1
... more SQL ...
LIMIT 1`
row := db.QueryRow(query, id)
err := row.Scan(
&user.Id,
&user.UserName,
&user.Password,
&user.FirstName,
&user.LastName,
... some 20 more lines of fields read into the struct ...
)
if err != nil {
return err
}
return nil
}
And there are several places in the system where I need to fetch user information as part of a larger query. That is, I am fetching some other type of object, but also a user account related to it.
That means, I have to repeat the whole rows.Scan(&user.Username, &user...) thing over and over again and it takes a whole page and it is error prone and if I ever change the user table structure I would have to change the code in a whole bunch of places. How can I make this more DRY?
Edit: I am not sure why this was marked as a duplicate, but since this edit is required, I will try to explain one more time. I am not asking how to scan a row into a struct. I already know how to do that, as the code above clearly shows. I am asking how to structure the struct scanning code in such a way that I do not have to repeat the same page of scanning code every time I am scanning the same type of struct.
Edit: also, yes, I am aware of sqlstruct and sqlx and similar libraries. I am deliberately avoiding these, because they depend on reflect package with well documented performance issues. And I intend to potentially scan millions of rows using these techniques (not millions of users, but this question extends to other record types).
Edit: so, yes, I know I should write a function. I am not sure what this function should take as arguments and what results it should return. Lets say that the other query I want to accommodate looks like this
SELECT
s.id,
s.name,
... more site fields ...
u.id,
u.username,
... more user fields ...
FROM site AS s
JOIN user AS u ON (u.id = s.user_id)
JOIN some_other_table AS st1 ON (site.id = st1.site_id)
... more SQL ...
And I have a site struct method that embeds a user struct. I don't want to repeat the user scanning code here. I want to call a function that will scan the user portion of the raw into a user struct the same way it does in the user method above.
To eliminate the repetition of the required steps to scan the *sql.Rows structure you could introduce two interfaces. One that describes the already implemented behaviour of *sql.Rows and *sql.Row.
// This interface is already implemented by *sql.Rows and *sql.Row.
type Row interface {
Scan(...interface{}) error
}
And another one that abstracts away the actual scanning step of the row(s).
// have your entity types implement this one
type RowScanner interface {
ScanRow(Row) error
}
An example implementation of the RowScanner interface could look like this:
type User struct {
Id uint
Username string
// ...
}
// Implements RowScanner
func (u *User) ScanRow(r Row) error {
return r.Scan(
&u.Id,
&u.Username,
// ...
)
}
type UserList struct {
Items []*User
}
// Implements RowScanner
func (list *UserList) ScanRow(r Row) error {
u := new(User)
if err := u.ScanRow(r); err != nil {
return err
}
list.Items = append(list.Items, u)
return nil
}
With these interfaces you can now dry your rows-scanning code for all of your types that implement the RowScanner interface by using these two functions.
func queryRows(query string, rs RowScanner, params ...interface{}) error {
rows, err := db.Query(query, params...)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rs.ScanRow(rows); err != nil {
return err
}
}
return rows.Err()
}
func queryRow(query string, rs RowScanner, params ...interface{}) error {
return rs.ScanRow(db.QueryRow(query, params...))
}
// example
ulist := new(UserList)
if err := queryRows(queryString, ulist, arg1, arg2); err != nil {
panic(err)
}
// or
u := new(User)
if err := queryRow(queryString, u, arg1, arg2); err != nil {
panic(err)
}
If you have composite types that you want to scan but you want to avoid having to repeat the enumeration of its elements' fields, then you could introduce a method that returns a type's fields and reuse that method where you need it. For example:
func (u *User) ScannableFields() []interface{} {
return []interface{}{
&u.Id,
&u.Username,
// ...
}
}
func (u *User) ScanRow(r Row) error {
return r.Scan(u.ScannableFields()...)
}
// your other entity type
type Site struct {
Id uint
Name string
// ...
}
func (s *Site) ScannableFields() []interface{} {
return []interface{}{
&p.Id,
&p.Name,
// ...
}
}
// Implements RowScanner
func (s *Site) ScanRow(r Row) error {
return r.Scan(s.ScannableFields()...)
}
// your composite
type UserWithSite struct {
User *User
Site *Site
}
// Implements RowScanner
func (u *UserWithSite) ScanRow(r Row) error {
u.User = new(User)
u.Site = new(Site)
fields := append(u.User.ScannableFields(), u.Site.ScannableFields()...)
return r.Scan(fields...)
}
// retrieve from db
u := new(UserWithSite)
if err := queryRow(queryString, u, arg1, arg2); err != nil {
panic(err)
}

Golang :How to parse/unmarshal/decode a json array API response?

I am trying to parse the response from Wikipedia's API located at https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia.org/all-access/all-agents/Smithsonian_Institution/daily/20160101/20170101 into an array of structs of which I will proceed to print out the view count
However, the code that I have tried to implement in order to achieve this returns nothing in the terminal when I build and run it?
The code I am failing to succeed with is as follows.
type Post struct {
Project string `json:"project"`
Article string `json:"article"`
Granularity string `json:"granularity"`
Timestamp string `json:"timestamp"`
Access string `json:"access"`
Agent string `json:"agent"`
Views int `json:"views"`
}
func main(){
//The name of the wikipedia post
postName := "Smithsonian_Institution"
//The frequency of
period := "daily"
//When to start the selection
startDate := "20160101"
//When to end the selection
endDate := "20170101"
url := fmt.Sprintf("https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia.org/all-access/all-agents/%s/%s/%s/%s", postName, period, startDate, endDate)
//Get from URL
req, err := http.Get(url)
if err != nil{
return
}
defer req.Body.Close()
var posts []Post
body, err := ioutil.ReadAll(req.Body)
if err != nil {
panic(err.Error())
}
json.Unmarshal(body, &posts)
// Loop over structs and display the respective views.
for p := range posts {
fmt.Printf("Views = %v", posts[p].Views)
fmt.Println()
}
}
What is the optimal method of receiving a json response from a API such as the one mentioned above and thereafter parsing that array into an array of structs, which can then be inserted into a datastore or printed out accordingly.
Thanks
Struct declarations can be nested inside one another.
The following struct should be convertable from that json:
type resp struct {
Items []struct {
Project string `json:"project"`
Article string `json:"article"`
Granularity string `json:"granularity"`
Timestamp string `json:"timestamp"`
Access string `json:"access"`
Agent string `json:"agent"`
Views int `json:"views"`
} `json:"items"`
}
I generated that with json-to-go, which is a great time saver when working with JSON APIs.
Your solution:
data := struct {
Items []struct {
Project string `json:"project"`
Article string `json:"article"`
Granularity string `json:"granularity"`
Timestamp string `json:"timestamp"`
Access string `json:"access"`
Agent string `json:"agent"`
Views int `json:"views"`
} `json:"items"`
}{}
// you don't need to convert body to []byte, ReadAll returns []byte
err := json.Unmarshal(body, &data)
if err != nil { // don't forget handle errors
}

How to set new value to struct member of explicit type from interface{} value (reflection)? Golang

I want to understand some subtle moments of using reflect package. Please, see example below, it describes better what I want to know:
type Robot struct {
id int
model string
}
func change(i interface{}, fields ...string) {
v := reflect.ValueOf(i).Elem()
// here I emulate function by slice that could return any value,
// so here I need to check if I can store incoming values to existing struct
returns := []interface{}{100, "Something"}
for i, name := range fields {
x := reflect.ValueOf(&returns[i]).Elem()
//check if value representing x is the same of struct member
v.FieldByName(name).Set(x)
// ^ here I want to store 100 to Robot.id when i = 0,
// and "Something" to Robot.model when i = 1
}
}
func main() {
robot := &Robot{id: 1, model: "T310"}
change(robot, "model", "id")
// now robot become as follows: &Robot{100, "Something"}
}
Why does it need for?
// It is need for retrieving values from sql DB into struct members
// (only for training purposes :))
// Example:
f := func(q string, structs interface{}, fields ...string) {
rows, _ := db.Query(q)
for i := 0; rows.Next(); i++ {
rows.Scan(&structs[i])
// very dirty here! it's hard to understand how to implement it
}
}
var robots = []*Robot
f("select id, model from robots", robots, "id", "model")
// now each member of robots var should contain values from DB
I tried to be descriptive and explain as short as possible. I hope you understand me..
You can only set exported fields via reflection, so capitalize those first. Otherwise, if you're counting on positional values, make sure they are properly aligned.
Something like this for example: http://play.golang.org/p/ItnjwwJnxe
type Robot struct {
ID int
Model string
}
func change(i interface{}, fields ...string) {
returns := []interface{}{100, "Something"}
v := reflect.ValueOf(i).Elem()
for i, name := range fields {
val := reflect.ValueOf(returns[i])
v.FieldByName(name).Set(val)
}
}
func main() {
robot := &Robot{ID: 1, Model: "T310"}
fmt.Println(robot)
change(robot, "ID", "Model")
fmt.Println(robot)
}

Unmarshalling top-level JSON array in Go

I'm learning Go by writing a simple http server and I need to handle some JSON responses.
With an object response, I can unmarshal it idiomatically with 2 lines of code:
structResult := Foo{}
json.Unmarshal(structBody, &structResult)
I don't know how to do the same for an array response (see the example below). Is there a way to specify (possibly via json tag) that top-level array should go into a given struct field?
package main
import "fmt"
import "encoding/json"
type Foo struct {
Id uint64 `json:"id"`
Name string `json:"name"`
}
type BaseResult struct {
Error string `json:"error"`
}
type FooResult struct {
BaseResult
Foos []Foo
}
func main() {
// Simple and works.
structBody := []byte(`{"id": 1,"name": "foo"}`)
structResult := Foo{}
json.Unmarshal(structBody, &structResult)
fmt.Printf("%#v\n", structResult)
// Doesn't work.
arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`)
arrayResult := FooResult{}
json.Unmarshal(arrayBody, &arrayResult)
fmt.Printf("%#v\n", arrayResult)
}
I know I could make FooResult an array:
type FooResult []Foo
but then I lose the ability to specify base object which I would like to use to store error message and such. I also know that I can unmarshal into &fooResult.Foos directly, but I want the code to work with both objects and arrays.
UPDATE
Implementing UnmarshalJSON as suggested by #dyoo partially solves my problem, but I was hoping that I could use BaseResult to store parse error in case JSON has a different structure:
arrayBody := []byte(`{"error": "foo"}`)
arrayResult := FooResult{}
json.Unmarshal(arrayBody, &arrayResult)
fmt.Printf("%#v\n", arrayResult)
Of course I could implement more complex logic inside UnmarshalJSON - but isn't there a simpler way to do it?
You can implement the json.Unmarshaler interface in your FooResult, to customize exactly how it responds to unmarshaling. (Similarly, there's a json.Marshaler interface.)
Add:
func (f *FooResult) UnmarshalJSON(bs []byte) error {
return json.Unmarshal(bs, &f.Foos)
}
after which your code should otherwise work. http://play.golang.org/p/oMdoB2e-rB
You might try something like:
func (f *FooResult) UnmarshalJSON(bs []byte) error {
err1 := json.Unmarshal(bs, &f.BaseResult)
err2 := json.Unmarshal(bs, &f.Foos)
if err1 != nil && err2 != nil {
// Arbitrarily choose an error.
return err1
}
return nil
}
although even this is beginning to look dubious. Handling union type results is not quite what the json library is designed to handle automatically for you. You'll need to explicitly code the coercion logic if your JSON has dynamic type.
See: How to unmarshall an array of different types correctly? and http://blog.golang.org/json-and-go for related issues.
Just specify Foos when you Unmarshal
package main
import "fmt"
import "encoding/json"
type Foo struct {
Id uint64 `json:"id"`
Name string `json:"name"`
}
type BaseResult struct {
Error string `json:"error"`
}
type FooResult struct {
BaseResult
Foos []Foo
}
func main() {
// Simple and works.
structBody := []byte(`{"id": 1,"name": "foo"}`)
structResult := Foo{}
json.Unmarshal(structBody, &structResult)
fmt.Printf("%#v\n", structResult)
// Doesn't work.
arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`)
arrayResult := FooResult{}
if err := json.Unmarshal(arrayBody, &arrayResult.Foos); err != nil {
arrayResult.BaseResult.Error = string(arrayBody)
}
fmt.Printf("%#v\n", arrayResult)
}

Resources