I'm currently writing against an xml service in which batched results are returned. I currently have the following:
type QueryEnvelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body *QueryBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type QueryBody struct {
QueryResult *QueryResult `xml:"queryResponse>result"`
}
type QueryResult struct {
QueryLocator QueryLocator `xml:"queryLocator"`
Done bool `xml:"done"`
Size int `xml:"size"`
Records interface{} `xml:"records"`
}
type QueryLocator string
func (r *Resource) Query(sql string, r interface{}) error {
// builds xml request
// sends xml request through Resource which contains the net client
// decodes the result into r (type for records in QueryResult)
}
func (r *Resource) QueryMore(q QueryLocator, r interface{}) error {
// same as above except takes queryLocator and makes call to different endpoint in order to continue retrieving results, when QueryResult.Done == true, done fetching results
}
Obviously this needs refactored since the Client needs to see whether Done == true so they can continue to fetch. I was thinking of adding the following the following, and moving Query and QueryMore to be a method of Querier:
type Querier struct {
r *Resource
Done bool
QueryLocator QueryLocator
}
func New(r *Resource) *Querier {}
Client side would then behave as such:
err := q.Query("sql statement", r)
if err != nil {
// handle
}
// do stuff with r
for q.Done == false {
q.QueryMore(r)
// do stuff with r
}
I'm wondering what the idiomatic approach would be here in order to best "stream" the results.
One option is to use the pattern the stdlib sql package uses to iterate over rows. This way you can unify the initial query with subsequent calls.
There's a Next() method, which populates the internal structure with the query results, and returns true if there's a result pending. In your case, you would still need an initial constructor, like Query, but that would just setup the data-structure. Calling Next() does the real work, and calling Scan(r) (or whatever you'd like to call reading the result) just presents to result. Once iteration is done, you have an Err() method to check for any operational errors.
Altering the example from the sql package a bit:
// setup the query, but delay any action until we start iterating.
query, err := NewQuery(queryParameters)
// check err of course
defer query.Close()
for query.Next() {
err = query.Scan(&r)
...
}
err = query.Err() // get any error encountered during iteration
You can also check out other drivers like mgo for variations on this pattern.
Related
I am writing a library in Go for using the Strava API. It's a simple API to expose the various objects (athlete, activity, and so on) that make up Strava's data. I am struggling to come up with a way that separates the mechanics of making a request so it can be reused to fetch the various different objects in the API. What I have so far:
type Model interface {
Url() *url.URL
Data() interface{} // pointer to location of unmarshaled response
}
// an activity (run, bike ride, etc)
type Activity struct {
Id int64 `json:"id"`
Name string `json:"name"`
Distance float64 `json:"distance"`
// ...
}
func (a *Activity) Url() *url.URL {
return url.Parse(fmt.Sprintf("https://www.strava.com/api/v3/activities/%d", a.Id))
}
func (a *Activity) Data() interface{} {
return a
}
// gear (shoes, bike, etc)
type Gear struct {
Id string `json:"id"`
Name string `json:"name"`
}
func (g *Gear) Url() *url.URL {
return url.Parse(fmt.Sprintf("https://www.strava.com/api/v3/gear/%s", g.Id))
}
func (g *Gear) Data() interface{} {
return g
}
// a page of activities
type ActivityPage struct {
AthleteId int64
PageNum int
Activities []Activity
}
func (p *ActivityPage) Url() *url.URL {
return url.Parse(fmt.Sprintf("https://www.strava.com/api/v3/athletes/%d/activities?page=%d&per_page=%d", p.AthleteId, p.PageNum, perPage))
}
func (p *ActivityPage) Data() interface{} {
return &p.Activities
}
type Client struct {
hc *http.Client
}
// error handling omitted
func (c *Client) fetch(m Model) error {
data, _ := c.fetchUrl(m.Url())
json.Unmarshal(data, m.Data())
return nil
}
func (c *Client) fetchUrl(u *url.URL) ([]byte, error) {
req := &http.Request{
// omit access token
Method: "GET",
URL: u,
}
resp, _ := c.hc.Do(req)
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
The Data() pointer is needed because the GET /athlete/activities endpoint returns a list of Activitys, rather than a specific model. ActivityPage is therefore a bit of a hack — an object that carries the data needed to build the URL along with a place to put the results. For cases where a GET returns a model the Data() pointer is just the object.
With this code, I can do:
client := Client{}
activity := Activity{Id: 1234}
client.fetch(activity)
fmt.Print(activity.Name)
page := ActivityPage{AthleteId: 1, PageNum: 1}
client.fetch(page)
fmt.Print(len(page.Activities))
But this feels.. icky. I don't like partially constructing the object and passing it to fetch() to be finished off, or that fetch doesn't actually return anything except an error on failure. The Data() pointer is a hack.
AIUI, interfaces are a way to write code that can work with objects of different types, but I feel like I want the inverse — to have some code (a Fetch() method or something) that is inherited by all objects with a certain trait.
How can I make this cleaner? I realise this is kind of open-ended so I'm more than happy to refine what the exact question is as appropriate. Are there canonical examples of building a REST client in Go? (I haven't found anything compelling so far)
this is a standard workaround typical for go, you pass a pointer to data you want to be modified by reflection, standard lib is built like that, you can at most make method to accept pointer to data and url directly to be more verbose and not interface. It will make it at least match cleaner what will get modified just from looking at api calls for user like:
func (c *Client) fetch(url string, responceBuffer interface{}) error {
data, err := c.fetchUrl(url)
if err != nil {
return err
}
return json.Unmarshal(data, responceBuffer)
}
I'm trying to write a "Binder" middleware that will validate any request query using a struct type with gin bindings/validators
So for example, let's say I have an endpoint group called /api/subject which requires the query string to have a subject code and an ID that will be validated using the following struct (called entity.Subject):
type Subject struct {
Code string `binding:"required,alphanum"`
ID string `binding:"required,alphanum,len=4"`
}
That's just one example, but I'd like to be able to pass any struct type to this middleware, because I'd like to access the query data on future handlers without worrying about query validation.
So I tried something like this:
func Binder(t reflect.Type) gin.HandlerFunc {
return func(c *gin.Context) {
obj := reflect.New(t).Elem().Interface()
if err := c.BindQuery(&obj); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
c.Set(t.Name(), obj)
}
}
And added this middleware like so:
apiGroup := router.Group("/api")
{
// other subgroups/endpoints
// ...
subjectGroup := apiGroup.Group("/subject", middleware.Binder(reflect.TypeOf(entity.Subject{})))
}
And later on, in another handler function, let's say GetSubject, I want to access the subject data passed by doing c.MustGet("Subject").(entity.Subject)
But this isn't working =(, when I print obj, it's just an empty interface, how would I do this?
I managed to do something similar!
I created the following middleware
var allowedTypes = []binding.Binding{
binding.Query,
binding.Form,
binding.FormPost,
binding.FormMultipart,
}
func Bind(name string, data interface{}, bindingType binding.Binding) gin.HandlerFunc {
return func(ctx *gin.Context) {
ok := false
for _, b := range allowedTypes {
if b == bindingType {
ok = true
}
}
if !ok {
ctx.AbortWithError(
http.StatusInternalServerError,
fmt.Errorf("Bind function only allows %v\n", allowedTypes),
)
}
_ = ctx.MustBindWith(data, bindingType)
ctx.Set(name, data)
}
}
Remember to pass a pointer to your desired type in the call, like so:
router.GET("/something", Bind("Object", &myObject, binding.Query))
I restricted only to a few binding types because they allow ShouldBind to be called multiple times, whereas JSON, XML and others consume the Request body.
This way you can pass multiple Bind middlewares and if the validation fails it automatically aborts with http.StatusBadRequest
Possibly related: How to use interface type as a model in mgo (Go)?
I have a struct like so:
type Game struct {
ID bson.ObjectId
Type string
Location string
Details interface{}
}
type FeudDetails struct {
...
}
type TriviaDetails struct {
...
}
type BingoDetails struct {
...
}
I want to use the Type field of Game to unserialize Details into a specific type (like an instance of FeudDetails or BingoDetails). It would still be an interface{} in Game, but then I could do this:
feudDetails, ok := game.Details.(FeudDetails)
if ok {
// we know this is a Feud game, and we have the details
feudDetails.Round++
}
The docs say that "it is possible to unmarshal or marshal values partially" using bson.Raw, but they don't provide any examples I've been able to find.
I've tried using:
func (game *Game) SetBSON(r bson.Raw) error {
err := r.Unserialize(game)
if err != nil {
return nil
}
games[game.Type].LoadDetails(game) // this calls a function based on the Type to
// create a concrete value for that game.
return nil
}
I get a (ahem) stack overflow here. I assume this is because r.Unserialize is recursively calling SetBSON.
My goal is to use standard unserializing on all fields except Details, and then be able to use game.Type to determine how to process Details. If I do something like this:
type GameDetails interface{}
type Game struct {
...
Details GameDetails
}
func (details *GameDetails) SetBSON(r bson.Raw) error {
// game isn't defined
games[game.Type].LoadDetails(r, details)
}
then how can I access the outer Type field to know which game type to unserialize it to?
I'll also accept the answer "you're doing it all wrong, and a better pattern in Go is XYZ..."
EDIT: I also tried deserializing normally, and then casting the interface{} version of Details using game.Details.(FeudDetails), but the conversion failed. I guess I can't do it that way because the underlying type after unserialization is not a FeudDetails but rather probably map[string]interface{}.
EDIT 2: I thought I'd be clever and pre-populate an object with the right types when retrieving from the database (game := Game{Details: FeudDetails: {}} prior to calling db...One(&game)) but my trickery did not work:
DEBU[Mar 31 22:19:09.442] Caching show gid=5e814448ef5b9858b7ff4e57
TRAC[Mar 31 22:19:09.442] Before database call dtype=main.FeudDetails
TRAC[Mar 31 22:19:09.446] After database call dtype=bson.M
Ignore Details during (un)marshalling
Change the definition of Game so bson doesn't try to do anything with the Details field:
type Game struct {
...
Details interface{} `json:"details" bson:"-"`
}
Unmarshal Details manually
func (game *Game) SetBSON(r bson.Raw) error {
// Unmarshall everything except Details
type tempGame Game
err := r.Unmarshal((*tempGame)(game)) // this is necessary to prevent recursion
if err != nil {
return err
}
// Get the raw data for Details
var d struct {
Details bson.Raw
}
if err := r.Unmarshal(&d); err != nil {
return err
}
gameType, ok := games[game.Type]
if ok {
// Use individual processing based on game Type
game.Details, err = gameType.LoadDetails(d.Details)
if err != nil {
return err
}
// fmt.Sprintf("%T", game.Details) => main.FeudDetails
}
return nil
}
Marshal Details manually
As far as I can tell, the only way to get bson to include Details after we told it to omit it in the original struct, is to create a whole other structure, copy the data over one by one, and use that type in GetBSON. It seems like there must be a better way.
I would like to pass a function pointer to a function to "anything".
It's easy to print something that gets passed in from just about anything (as in https://play.golang.org/p/gmOy6JWxGm0):
func printStuff(stuff interface{}) {
fmt.Printf("Testing : %v", stuff)
}
Let's say, though, that I want to do this:
Have multiple structs
Have data loaded from various functions
Have a generic print that calls the function for me
I tried this in a Play (https://play.golang.org/p/l3-OkL6tsMW) and I get the following errors:
./prog.go:35:12: cannot use getStuff1 (type func() SomeObject) as type FuncType in argument to printStuff
./prog.go:36:12: cannot use getStuff2 (type func() SomeOtherObject) as type FuncType in argument to printStuff
In case the Play stuff gets deleted, here's the code I'm trying to figure out how to get to work:
package main
import (
"fmt"
)
type SomeObject struct {
Value string
}
type SomeOtherObject struct {
Value string
}
type FuncType func() interface{}
func getStuff1() SomeObject {
return SomeObject{
Value: "Hello, world!",
}
}
func getStuff2() SomeOtherObject {
return SomeOtherObject{
Value: "Another, hello!",
}
}
func printStuff(toCall FuncType) {
stuff := toCall()
fmt.Printf("Testing : %v", stuff)
}
func main() {
printStuff(getStuff1)
printStuff(getStuff2)
}
What is the secret sauce to get this stuff passed in properly?
Larger Goal Explanation
So what I am trying to accomplish here is reduction of boilerplate code that lives inside a gigantic file. Unfortunately I cannot refactor it further at this point due to other restrictions and I was wondering if this were possible at all considering the error messages and what I had read seemed to dictate otherwise.
There's a large amount of copy-and-paste code that looks like this:
func resendContraDevice(trap *TrapLapse, operation *TrapOperation) {
loaded := contra.Load()
err := trap.SnapBack(operation).send(loaded);
// default error handling
// logging
// boilerplate post-process
}
func resendPolicyDevice(trap *TrapLapse, operation *TrapOperation) {
loaded := policy.Load()
err := trap.SnapBack(operation).send(loaded);
// default error handling
// logging
// boilerplate post-process
}
// etc.
In these, the Load() functions all return a different struct type and they are used elsewhere throughout the application.
I want hoping to get something where I could have:
loaded := fn()
err := trap.SnapBack(operation).send(loaded);
// default error handling
// logging
// boilerplate post-process
Signature for send is, which accepts an interface{} argument:
func (s SnapBack) send(data interface{}) error
I don't know if you have control over the return values of contra.Load() and policy.Load(), for instance, so there may be a better approach, but assuming those cannot be modified, this would allow you to eliminate a lot of boilerplate, without any fancy manipulation:
func boilerplate(tram *TrapLapse, operation *TrapOperation, loader func() interface{}) {
loaded := loader()
err := trap.SnapBack(operation).send(loaded);
// default error handling
// logging
// boilerplate post-process
}
func resendContraDevice(trap *TrapLapse, operation *TrapOperation) {
boilerplate(trap, operation, func() interface{} { return contra.Load() })
}
func resendPolicyDevice(trap *TrapLapse, operation *TrapOperation) {
boilerplate(trap, operation, func() interface{} { return policy.Load() })
}
If there's nothing more complex, you can also simplify this even further:
func boilerplate(tram *TrapLapse, operation *TrapOperation, loaded interface{}) {
err := trap.SnapBack(operation).send(loaded);
// default error handling
// logging
// boilerplate post-process
}
func resendContraDevice(trap *TrapLapse, operation *TrapOperation) {
boilerplate(trap, operation, contra.Load())
}
func resendPolicyDevice(trap *TrapLapse, operation *TrapOperation) {
boilerplate(trap, operation, policy.Load())
}
Due to error handling in Go, I often end up with multiple values functions. So far, the way I have managed this has been very messy and I am looking for best practices to write cleaner code.
Let's say I have the following function:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}
How can I assign a new variable to item.Value elegantly. Before introducing the error handling, my function just returned item and I could simply do this:
val := Get(1).Value
Now I do this:
item, _ := Get(1)
val := item.Value
Isn't there a way to access directly the first returned variable?
In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t *Template, err error) *Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
Back to your case
IF you can be certain Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error but raise a runtime panic if it still occurs:
func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}
But you should not use this in all cases, just when you're sure it succeeds. Usage:
val := Must(Get(1)).Value
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic Must() function:
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
This is available in github.com/icza/gog, as gog.Must() (disclosure: I'm the author).
Alternative / Simplification
You can even simplify it further if you incorporate the Get() call into your helper function, let's call it MustGet:
func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}
Usage:
val := MustGet(1).Value
See some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
Yes, there is.
Surprising, huh? You can get a specific value from a multiple return using a simple mute function:
package main
import "fmt"
import "strings"
func µ(a ...interface{}) []interface{} {
return a
}
type A struct {
B string
C func()(string)
}
func main() {
a := A {
B:strings.TrimSpace(µ(E())[1].(string)),
C:µ(G())[0].(func()(string)),
}
fmt.Printf ("%s says %s\n", a.B, a.C())
}
func E() (bool, string) {
return false, "F"
}
func G() (func()(string), bool) {
return func() string { return "Hello" }, true
}
https://play.golang.org/p/IwqmoKwVm-
Notice how you select the value number just like you would from a slice/array and then the type to get the actual value.
You can read more about the science behind that from this article. Credits to the author.
No, but that is a good thing since you should always handle your errors.
There are techniques that you can employ to defer error handling, see Errors are values by Rob Pike.
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
In this example from the blog post he illustrates how you could create an errWriter type that defers error handling till you are done calling write.
No, you cannot directly access the first value.
I suppose a hack for this would be to return an array of values instead of "item" and "err", and then just do
item, _ := Get(1)[0]
but I would not recommend this.
How about this way?
package main
import (
"fmt"
"errors"
)
type Item struct {
Value int
Name string
}
var items []Item = []Item{{Value:0, Name:"zero"},
{Value:1, Name:"one"},
{Value:2, Name:"two"}}
func main() {
var err error
v := Get(3, &err).Value
if err != nil {
fmt.Println(err)
return
}
fmt.Println(v)
}
func Get(value int, err *error) Item {
if value > (len(items) - 1) {
*err = errors.New("error")
return Item{}
} else {
return items[value]
}
}
Here's a generic helper function with assumption checking:
func assumeNoError(value interface{}, err error) interface{} {
if err != nil {
panic("error encountered when none assumed:" + err.Error())
}
return value
}
Since this returns as an interface{}, you'll generally need to cast it back to your function's return type.
For example, the OP's example called Get(1), which returns (Item, error).
item := assumeNoError(Get(1)).(Item)
The trick that makes this possible: Multi-values returned from one function call can be passed in as multi-variable arguments to another function.
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
This answer borrows heavily from existing answers, but none had provided a simple, generic solution of this form.