如何使这段 Go 代码更加 DRY(Don’t Repeat Yourself)?

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

How do I make this Go code more DRY?

问题

我正在为一个REST API实现一个Go的包装器。它基本上解析JSON并返回相应的结构体类型。我发现自己经常这样做:

// GetBlueprintDetails返回有关蓝图的详细信息
func (c *Client) GetBlueprintDetails(projectID string, blueprintID string) (*BlueprintDetails, *APIError) {
    path := fmt.Sprintf("projects/%s/blueprints/%s", projectID, blueprintID)
    res, err := c.Request("GET", path, nil, nil)
    if err != nil {
        return nil, err
    }
    var ret BlueprintDetails
    e := json.Unmarshal(res.Body, &ret)
    if e != nil {
        return nil, &APIError{Error: &e}
    }
    return &ret, nil
}

// GetProjects返回用户的项目列表
func (c *Client) GetProjects() (*[]Project, *APIError) {
    res, err := c.Request("GET", "projects", nil, nil)
    if err != nil {
        return nil, err
    }
    var ret []Project
    e := json.Unmarshal(res.Body, &ret)
    if e != nil {
        return nil, &APIError{Error: &e}
    }
    return &ret, nil
}

这两个函数之间唯一的区别就是解析后的结构体类型。我知道Go中没有泛型,但肯定有一种模式可以使代码更加DRY。

有什么想法吗?

英文:

I'm implementing a Go wrapper for a REST API. It basically parses JSON and should return the appropriate struct type. I find myself doing a lot of this:

// GetBlueprintDetails returns details about a blueprint
func (c *Client) GetBlueprintDetails(projectID string, blueprintID string) (*BlueprintDetails, *APIError) {
	path := fmt.Sprintf("projects/%s/blueprints/%s", projectID, blueprintID)
	res, err := c.Request("GET", path, nil, nil)
	if err != nil {
		return nil, err
	}
	var ret BlueprintDetails
	e := json.Unmarshal(res.Body, &ret)
	if e != nil {
		return nil, &APIError{Error: &e}
	}
	return &ret, nil
}

// GetProjects returns a list of projects for the user
func (c *Client) GetProjects() (*[]Project, *APIError) {
	res, err := c.Request("GET", "projects", nil, nil)
	if err != nil {
		return nil, err
	}
	var ret []Project
	e := json.Unmarshal(res.Body, &ret)
	if e != nil {
		return nil, &APIError{Error: &e}
	}
	return &ret, nil
}

The only difference between the two functions is the type of the unmarshaled struct basically. I know there are no generic in Go, but there has to be a pattern to make this more DRY.

Any ideas?

答案1

得分: 5

你可以创建一个名为MakeRequest的函数,用于执行HTTP请求并将JSON解析为结构体。

以下是你可以编写的MakeRequest函数的示例代码:

// GetBlueprintDetails 返回关于蓝图的详细信息
func (c *Client) GetBlueprintDetails(projectID string, blueprintID string) (*BlueprintDetails, *APIError) {
    path := fmt.Sprintf("projects/%s/blueprints/%s", projectID, blueprintID)
    bluePrintDetails := new(BlueprintDetails)
    err := c.MakeRequest("GET", path, bluePrintDetails)
    return bluePrintDetails, err
}

// GetProjects 返回用户的项目列表
func (c *Client) GetProjects() (*[]Project, *APIError) {
    projects := make([]Project, 0)
    err := c.MakeRequest("GET", "project", &projects)
    return &projects, err
}

func (c *Client) MakeRequest(method string, path string, response interface{}) *APIError {
    res, err := c.Request(method, path, nil, nil)
    if err != nil {
        return nil, err
    }
    e := json.Unmarshal(res.Body, response)
    if e != nil {
        return &APIError{Error: &e}
    }
    return nil
}

这段代码展示了如何使用MakeRequest函数。你可以根据自己的需求进行修改和扩展。

英文:

You may create a MakeRequest function that does the http request part and unmarshal the json to struct

Here is how you may do it, have a look at the MakeRequest function

// GetBlueprintDetails returns details about a blueprint
func (c *Client) GetBlueprintDetails(projectID string, blueprintID string) (*BlueprintDetails, *APIError) {
	path := fmt.Sprintf("projects/%s/blueprints/%s", projectID, blueprintID)
	bluePrintDetails = new(BlueprintDetails)
	err := c.MakeRequest("GET", path, bluePrintDetails)
	return bluePrintDetails, err
}

// GetProjects returns a list of projects for the user
func (c *Client) GetProjects() (*[]Project, *APIError) {
	projects = make([]Project, 0)
	err := c.MakeRequest("GET", "project", &projects)
	return &projects, err
}

func (c *Client) MakeRequest(method string, path string, response interface{}) *APIError {
	res, err := c.Request(method, path, nil, nil)
	if err != nil {
		return nil, err
	}
	e := json.Unmarshal(res.Body, response)
	if e != nil {
		return &APIError{Error: &e}
	}
	return nil
}

huangapple
  • 本文由 发表于 2016年12月30日 13:31:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/41391119.html
匿名

发表评论

匿名网友

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

确定