Skip to content

Instantly share code, notes, and snippets.

@boseabhishek
Last active July 25, 2019 16:46
Show Gist options
  • Save boseabhishek/7b9c8530be4cf9eb3443f4823fb1e5c2 to your computer and use it in GitHub Desktop.
Save boseabhishek/7b9c8530be4cf9eb3443f4823fb1e5c2 to your computer and use it in GitHub Desktop.
Async parallel calls to invoke two APIs using anonymous goroutine functions and channels to pipe the response
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/julienschmidt/httprouter"
)
func doGet(url string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return []byte{}, fmt.Errorf("Failed to create HTTP Request %s", err)
}
var getClient = &http.Client{
Timeout: time.Second * 10,
}
resp, err := getClient.Do(req)
if err != nil {
return []byte{}, fmt.Errorf("The HTTP request failed with error %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, fmt.Errorf("Cannot raed response body due to %s", err)
}
if 200 != resp.StatusCode {
return body, fmt.Errorf("HTTP Status Not_OK %s", err)
}
return body, nil
}
func formURL(id string) string {
return fmt.Sprintf("https://jsonplaceholder.typicode.com/todos/%s", id)
}
func GetTodos(id string) []map[string]interface{} {
//create an empty response of string type
resp := []map[string]interface{}{}
//step 1: create channels which can be used to pass a string around
//(Channels are the pipes that connect concurrent goroutines)
//Channels are typed by the values they convey.
chn := make(chan map[string]interface{}, 2)
errCh := make(chan error, 2)
//two parallel calls
go consumeRequest(id, chn, errCh)
go consumeRequest(id, chn, errCh)
//ading up the contents of the channels which are string
for i := 0; i < 2; i++ {
select {
case err := <-errCh:
fmt.Println(err)
case r := <-chn:
resp = append(resp, r)
}
}
return resp
}
func consumeRequest(id string, out chan<- map[string]interface{}, errCh chan<- error) {
body, err := doGet(formURL(id))
if err != nil {
errCh <- err
return
}
r := map[string]interface{}{}
if err := json.Unmarshal(body, &r); err != nil {
errCh <- err
return
}
out <- r
}
func TodosHandler(writer http.ResponseWriter, req *http.Request, param httprouter.Params) {
id := param.ByName("id")
res := GetTodos(id)
json.NewEncoder(writer).Encode(res)
}
func main() {
//creates a new router
router := httprouter.New()
router.GET("/todos/:id", TodosHandler)
log.Fatal(http.ListenAndServe(":9093", router))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment