Skip to content

Instantly share code, notes, and snippets.

@arielsrv
Created October 20, 2022 07:42
Show Gist options
  • Save arielsrv/356784d3efe2f64ef1d4705934179385 to your computer and use it in GitHub Desktop.
Save arielsrv/356784d3efe2f64ef1d4705934179385 to your computer and use it in GitHub Desktop.
rest_client rest_client
package main
import (
"bytes"
"container/list"
"encoding/json"
"io"
"log"
"net/http"
"sync"
"sync/atomic"
"time"
"unsafe"
)
func main() {
headers := make(http.Header)
headers.Add("Authorization", "Bearer fa41044ca1280a218dbe6cc58cfce9a8465f440a281f858931d1e2be6e47bb5f")
builder := &RequestBuilder{
BaseURL: "https://gorest.co.in/public/v2",
Headers: headers,
}
// Blocking GET
rb := builder.Get("/users")
log.Printf("Get(): %d\n", rb.StatusCode)
// Blocking POST
rb = builder.
Post("/users",
NewUser("John Doe", "john@doe.com", "male", "active"))
log.Printf("Post(): %d\n", rb.StatusCode)
// Blocking GET futures
var futures []*FutureResponse
builder.ForkJoin(func(c *Concurrent) {
futures = append(futures, c.Get("/users"))
futures = append(futures, c.Get("/users"))
futures = append(futures, c.Get("/users"))
futures = append(futures, c.Get("/users"))
futures = append(futures, c.Get("/users"))
})
for i := range futures {
log.Printf("ForkJoin(%d): %d\n", i, futures[i].Response().StatusCode)
}
// Non-blocking GET
builder.AsyncGet("/users", func(r *Response) {
log.Printf("AsyncGet(): %d\n", r.StatusCode)
})
time.Sleep(time.Millisecond * 50)
}
type User struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Gender string `json:"gender,omitempty"`
Status string `json:"status,omitempty"`
}
func NewUser(name string, email string, gender string, status string) *User {
return &User{Name: name, Email: email, Gender: gender, Status: status}
}
type Concurrent struct {
list list.List
wg sync.WaitGroup
requestBuilder *RequestBuilder
}
func (c *Concurrent) Get(url string) *FutureResponse {
fr := new(FutureResponse)
future := func() {
defer c.wg.Done()
message := c.requestBuilder.Get(url)
atomic.StorePointer(&fr.pointer, unsafe.Pointer(message))
}
c.list.PushBack(future)
return fr
}
type FutureResponse struct {
pointer unsafe.Pointer
}
func (fr *FutureResponse) Response() *Response {
return (*Response)(fr.pointer)
}
type RequestBuilder struct {
BaseURL string
Headers http.Header
Client *http.Client
clientMtxOnce sync.Once
}
func (rb *RequestBuilder) Get(path string) *Response {
return rb.execute(http.MethodGet, path, nil)
}
func (rb *RequestBuilder) Post(path string, body interface{}) *Response {
return rb.execute(http.MethodPost, path, body)
}
func (rb *RequestBuilder) execute(verb string, url string, body interface{}) (result *Response) {
result = new(Response)
client := rb.getClient()
raw, err := json.Marshal(body)
if err != nil {
result.Err = err
return
}
request, err := http.NewRequest(verb, rb.BaseURL+url, bytes.NewBuffer(raw))
if err != nil {
result.Err = err
return
}
if rb.Headers != nil {
for key, values := range map[string][]string(rb.Headers) {
for _, value := range values {
request.Header.Add(key, value)
}
}
}
response, err := client.Do(request)
if err != nil {
result.Err = err
return
}
defer response.Body.Close()
bytes, err := io.ReadAll(response.Body)
if err != nil {
result.Err = err
return
}
result.Response = response
result.Bytes = bytes
return result
}
func (rb *RequestBuilder) getClient() *http.Client {
rb.clientMtxOnce.Do(func() {
rb.Client = &http.Client{}
})
return rb.Client
}
func (rb *RequestBuilder) AsyncGet(url string, f func(*Response)) {
go f(rb.Get(url))
}
func (rb *RequestBuilder) AsyncPost(url string, body interface{}, f func(*Response)) {
go f(rb.Post(url, body))
}
func (rb *RequestBuilder) ForkJoin(f func(*Concurrent)) {
c := new(Concurrent)
c.requestBuilder = rb
f(c)
c.wg.Add(c.list.Len())
for node := c.list.Front(); node != nil; node = node.Next() {
go node.Value.(func())()
}
c.wg.Wait()
}
type Response struct {
*http.Response
Err error
Bytes []byte
}
func (r *Response) Deserialize(reference interface{}) error {
err := json.Unmarshal(r.Bytes, &reference)
if err != nil {
return err
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment