Go - passing generic struct to function

12,406

The Marshal function also receives its parameters as interface{} therefore there's no way to detect if you are passing something invalid at compile time, it's all caught at runtime.

One thing you can do to check if an invalid type was passed to Marshal is to check the error type, Marshal returns an UnsupportedTypeError when you try to Marshal an invalid type (like chan or func) so you can check for that error when Marshaling.

So you could try something like that:

if err != nil {
    _, ok := err.(*json.UnsupportedTypeError)
    if ok {
        return []byte("Tried to Marshal Invalid Type")
    } else {
        return []byte("Venue does not exist")
    }
}
Share:
12,406
Ralph King
Author by

Ralph King

Updated on June 22, 2022

Comments

  • Ralph King
    Ralph King almost 2 years

    Considering the following code, which is responding to GET '/venues/:id':

    func venueShow(w http.ResponseWriter, req *http.Request) {
    
      // get ID from params
      vars := mux.Vars(req)
      id := vars["id"]
    
      // initialise new struct
      var venue Venue
    
      // select by id and scan into struct
      db.First(&venue, id).Scan(&venue)
    
      // turn it to json
      response := structToJSON(&venue)
    
      // write headers and provide response
      w.Header().Set("Content-Type", "application/json")
      w.Write(response)
    }
    

    and:

    func structToJSON (s interface{}) (response []byte) {
      // turn it into pretty-ish json
      response, err := json.MarshalIndent(&s, "", "  ")
      if err != nil {
       return []byte("Venue does not exist")
      }
      // return the json as the reponse
      return response
    }
    

    My structToJSON function is taking an empty interface as the argument, because I want to pass various different structs to the function and have them spewed out as JSON.

    However, it doesn't strike me as very safe. If anything satisfies an empty interface, I could pass whatever I wanted into that function, and all sorts of errors might happen when json.Marshal tries to do it's business. This (I suppose) would be caught by the compiler rather than at runtime, but is there a safer way?

    I could duplicate the structToJSON method for each different type of Struct/Model that I pass to it, but that's not very DRY.

    Thanks

  • Ralph King
    Ralph King over 8 years
    Ah ok, didn't think of that. So there's no real problem with using an empty interface as an argument, as stuff in the standard library does it loads I suppose. Thanks. I'll mark this as correct!
  • hbejgel
    hbejgel over 8 years
    Yeah, sice go doesn't have generics and doesn't allow method overload we're pretty stuck passing interface{} as parameters.