抽象化GET、读取和解析逻辑

huangapple go评论89阅读模式
英文:

Abstract GET, read, unmarshal logic away

问题

我的应用程序执行了大量的API调用,我正在尝试消除其中的一些重复代码。从概念上讲,以下步骤在每次调用中都会重复执行:

  1. 发送GET请求
    1. 检查错误
  2. 读取响应的主体内容
    1. 检查错误
  3. 反序列化为目标结构体
    1. 检查错误
  4. 返回目标结构体

所有调用之间唯一的显著区别就是目标结构体。
在代码中,它看起来像这样:

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 // 这是唯一的真正区别!
    err = json.Unmarshal(body, &users)
    if err != nil {
        return nil, err 
    }
    
    return users, nil 
}

我希望能够像这样使用getUsers(url, users)getProjects(url, projects)

我尝试过使用一个接受interface{}类型参数的函数,然后稍后将其转换回正确的类型,但是没有成功:

func request(url string, target interface{}) (interface{}, error) {
     // 执行与上述相同的逻辑。除了:
     err = json.Unmarshal(body, &target)
     // ...
     return target, nil
}

然后可以这样做:

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

我有一种感觉,这应该是可行的...

英文:

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
  2. Check for errors
  3. Read the body of the response
  4. Check for errors
  5. Deserialize into target struct
  6. Check for errors
  7. 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...

答案1

得分: 0

不要使用interface{}的地址,它已经包含了解组所需的指针。

func request(url string, target interface{}) (interface{}, error) {
    // 获取响应
    err := json.Unmarshal(body, target)
    ...
}

示例

英文:

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

huangapple
  • 本文由 发表于 2015年1月5日 23:45:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/27782918.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定