I have a function which may or may not be called as an asynchronous go-routine.
func APICall(request *HTTPRequest) *HTTPResponse
*HTTPRequest
is a pointer to a struct which contains various pieces of data required in order to build a request:
type HTTPRequest struct {
// Represents a request to the twitter API
method string
baseurl string
urlParams map[string]string
bodyParams map[string]string
authParams map[string]string
responseChan chan *HTTPResponse
}
If called as a goroutine, i.e a channel is passed in; we build the request and write the response into the *HTTPResponse object (also a struct) of the provided channel. What is the most graceful / idiomatic way to accept a call to the function without a channel (ie. Not async)
At the moment, we do something like this within the body of APICall to deal with both kinds of function call:
if request.responseChan != nil { // If a response channel has been specified, write to that channel
request.responseChan <- &twitterHTTPResponse{body, nil}
return nil // Not returning a struct
} else {
return &twitterHTTPResponse{body, nil} // Return a pointer to a new struct representing the response
}
Are we along the right lines?
The idiomatic approach is to provide a synchronous API:
type HTTPRequest struct {
// Represents a request to the twitter API
method string
baseurl string
urlParams map[string]string
bodyParams map[string]string
authParams map[string]string
}
func APICall(request *HTTPRequest) *HTTPResponse {
...
return &twitterHTTPResponse{body, nil}
}
The caller an can easily create a goroutine if it needs to run the call concurrently. For example:
r := make(chan *HTTPResponse)
go func() {
r <- APICall(req)
}()
... do some other work
resp := <- r
Synchronous APIs are idiomatic for a couple of reasons: