Created
October 20, 2022 07:42
-
-
Save arielsrv/356784d3efe2f64ef1d4705934179385 to your computer and use it in GitHub Desktop.
rest_client
rest_client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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