抽象获取,读取,解组逻辑

My application does a whole lot of API calls and I'm trying to get rid of some duplication surrounding that. Conceptually the following steps are repeated every single time:

  1. Do a GET request
    1. Check for errors
  2. Read the body of the response
    1. Check for errors
  3. Deserialize into target struct
    1. Check for errors
  4. Return target struct

The only significant difference between all the calls is the target struct. In code it looks something like this:

func getUsers() ([]User, error) {
    resp, err := http.Get(someUrl)
    if err != nil {
        return nil, err 
    }
    if resp.StatusCode != 200 {
        return nil, errors.New("Search return non 200 status code")
    }

    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err 
    }

    var users []User // This is the only real difference!
    err = json.Unmarshal(body, &users)
    if err != nil {
        return nil, err 
    }

    return users, nil 
}

I would love to do something like getUsers(url, users) and getProjects(url, projects).

I've been trying with a function which takes a interface{} and cast it later to the correct type again but to no avail:

func request(url string, target interface{}) (interface{}, error) {
     // do all the same logic as above. Except:
     err = json.Unmarshal(body, &target)
     // ...
     return target, nil
}

And then do something like:

 var users []User
 result, err := request(url, users)
 v, ok := result.([]User)

I have the feeling this should be possible...

Don't use the address of the interface{}, it already contains the pointer needed for unmarshaling.

func request(url string, target interface{}) (interface{}, error) {
     // get response
     err = json.Unmarshal(body, target)
    ...

example