> "I want to interact with a REST API and pull a field out of its response JSON" is an incredibly common workflow, and yet to do that in golang is far from trivial
// Interact with a REST API and pull a field out of its response JSON.
func interact(url string) (field string, err error) {
resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("error making HTTP request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("error querying API: %d %s", resp.StatusCode, resp.Status)
}
var response struct {
Field string `json:"the_field"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return "", fmt.Errorf("error parsing API response: %w", err)
}
return response.Field, nil
}
IMO this is a good level of abstraction for a language's standard library. Each of the concrete steps required for the process are simply and adequately represented. Each can fail, and that failure is idiomatically managed directly and inline, which, when applied to an entire program, significantly improves reliability. If you find yourself doing this often, you can easily write a function to do the grunt work. Probably
> Same deal with a worker pool. Concurrency is great, but instead of providing a robust, well written solution as part of the language itself, it gives you a toy like this
Go's concurrency primitives are very low level. This can be bad, but it can also be good: not all worker pools, for example, need the same set of features.
Go's concurrency primitives are very low level. This can be bad, but it can also be good: not all worker pools, for example, need the same set of features.