Advertisement
aldikhan13

Http Client Request Custom

Nov 9th, 2024 (edited)
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 7.17 KB | Source Code | 0 0
  1. /*
  2. connect with me through social media networks
  3.  
  4. GitHub: https://github.com/restuwahyu13
  5. Linkedin: https://www.linkedin.com/in/restuwahyu13
  6. UpWork: https://www.upwork.com/freelancers/~016e91d99e2bf0bdcf
  7. */
  8.  
  9.  
  10. package helpers
  11.  
  12. import (
  13.     "bytes"
  14.     "context"
  15.     "crypto/tls"
  16.     "errors"
  17.     "fmt"
  18.     "io"
  19.     "net"
  20.     "net/http"
  21.     "net/http/httputil"
  22.     "strings"
  23.     "time"
  24.  
  25.     "github.com/sirupsen/logrus"
  26.  
  27.     ahelpers "github.com/x-id/worker/internal/domain/adapters/helpers"
  28.     dto "github.com/x-id/worker/internal/domain/dto/helpers"
  29. )
  30.  
  31. type (
  32.     roundTripper struct {
  33.         Transport http.RoundTripper
  34.         Headers   map[string]string
  35.     }
  36.  
  37.     httpClient struct {
  38.         transport *roundTripper
  39.         ctx       context.Context
  40.     }
  41. )
  42.  
  43. func NewHttpClient(ctx context.Context) ahelpers.HttpClient {
  44.     transport := &roundTripper{
  45.         Transport: &http.Transport{
  46.             ReadBufferSize: http.DefaultMaxHeaderBytes,
  47.             TLSClientConfig: &tls.Config{
  48.                 MinVersion:         tls.VersionTLS12,
  49.                 InsecureSkipVerify: true,
  50.             },
  51.         },
  52.     }
  53.  
  54.     return &httpClient{ctx: ctx, transport: transport}
  55. }
  56.  
  57. /**
  58. * ===========================================
  59. * HANDLER METHOD - WithoutFormData
  60. * ===========================================
  61. **/
  62.  
  63. func (h *httpClient) WithoutFormData(options *dto.HttpClientOptions, dest any) (*http.Response, error) {
  64.     var (
  65.         req       *http.Request   = nil
  66.         bodyBytes *bytes.Buffer   = nil
  67.         dataByte  []byte          = nil
  68.         err       error           = nil
  69.         parser    ahelpers.Parser = NewParser()
  70.     )
  71.  
  72.     timeout := time.Second * 65
  73.     ctx, cancel := context.WithTimeout(h.ctx, timeout)
  74.     defer cancel()
  75.  
  76.     h.transport.Headers = options.Configs.Headers
  77.  
  78.     if options.Method != http.MethodGet && options.Method != http.MethodHead && options.Method != http.MethodOptions {
  79.         if options.DataJson != nil {
  80.             data, err := NewParser().Marshal(options.DataJson)
  81.             if err != nil {
  82.                 return nil, err
  83.             }
  84.             dataByte = data
  85.         }
  86.  
  87.         bodyBytes = bytes.NewBuffer(dataByte)
  88.     } else {
  89.         bodyBytes = bytes.NewBuffer(nil)
  90.     }
  91.  
  92.     for {
  93.         select {
  94.         case <-ctx.Done():
  95.             if err := ctx.Err(); err != nil {
  96.                 h.ctx = context.Background()
  97.  
  98.                 req, err = http.NewRequest(options.Method, options.Url, bodyBytes)
  99.                 if err != nil {
  100.                     if err.(net.Error).Timeout() {
  101.                         return nil, errors.New("External network timeout")
  102.                     }
  103.  
  104.                     return nil, err
  105.                 }
  106.  
  107.                 return h.withoutFormData(req, parser, timeout, dest)
  108.             }
  109.  
  110.         default:
  111.             req, err = http.NewRequestWithContext(h.ctx, options.Method, options.Url, bodyBytes)
  112.             if err != nil {
  113.                 if err.(net.Error).Timeout() {
  114.                     return nil, errors.New("External network timeout")
  115.                 }
  116.  
  117.                 return nil, err
  118.             }
  119.  
  120.             return h.withoutFormData(req, parser, timeout, dest)
  121.         }
  122.     }
  123. }
  124.  
  125. func (h *httpClient) withoutFormData(req *http.Request, parser ahelpers.Parser, timeout time.Duration, dest any) (*http.Response, error) {
  126.     req.Header.Add("Content-Type", "application/json")
  127.     res, err := h.transport.RoundTrip(req)
  128.     if err != nil {
  129.         return nil, err
  130.     }
  131.  
  132.     h.transport.httpRequestDump(req)
  133.     h.transport.httpResponseDump(res)
  134.  
  135.     client := http.Client{Transport: h.transport, Timeout: timeout}
  136.     if res, err := client.Do(req); err != nil {
  137.         return res, err
  138.     }
  139.  
  140.     buffer, err := io.ReadAll(res.Body)
  141.     if err != nil {
  142.         return nil, err
  143.     }
  144.     defer res.Body.Close()
  145.  
  146.     res.Body = io.NopCloser(io.MultiReader(bytes.NewReader(buffer), res.Body))
  147.  
  148.     if !strings.Contains(string(buffer), "html") {
  149.         if err := parser.Decode(res.Body, dest); err != nil {
  150.             return nil, err
  151.         }
  152.         defer res.Body.Close()
  153.  
  154.         return res, nil
  155.     } else {
  156.         return res, errors.New("Output is not as expected")
  157.     }
  158. }
  159.  
  160. /**
  161. * ===========================================
  162. * HANDLER METHOD - WithFormData
  163. * ===========================================
  164. **/
  165.  
  166. func (h *httpClient) WithFormData(options *dto.HttpClientOptions, dest any) (*http.Response, error) {
  167.     var (
  168.         req    *http.Request   = nil
  169.         err    error           = nil
  170.         parser ahelpers.Parser = NewParser()
  171.     )
  172.  
  173.     timeout := time.Second * 65
  174.     ctx, cancel := context.WithTimeout(h.ctx, timeout)
  175.     defer cancel()
  176.  
  177.     h.transport.Headers = options.Configs.Headers
  178.  
  179.     for {
  180.         select {
  181.         case <-ctx.Done():
  182.             if err := ctx.Err(); err != nil {
  183.                 h.ctx = context.Background()
  184.  
  185.                 req, err = http.NewRequest(options.Method, options.Url, bytes.NewBuffer([]byte(options.DataForm.Encode())))
  186.                 if err != nil {
  187.                     if err.(net.Error).Timeout() {
  188.                         return nil, errors.New("External network timeout")
  189.                     }
  190.  
  191.                     return nil, err
  192.                 }
  193.  
  194.                 return h.formData(req, parser, timeout, dest)
  195.             }
  196.  
  197.         default:
  198.             req, err = http.NewRequestWithContext(h.ctx, options.Method, options.Url, bytes.NewBuffer([]byte(options.DataForm.Encode())))
  199.             if err != nil {
  200.                 if err.(net.Error).Timeout() {
  201.                     return nil, errors.New("External network timeout")
  202.                 }
  203.  
  204.                 return nil, err
  205.             }
  206.  
  207.             return h.formData(req, parser, timeout, dest)
  208.         }
  209.     }
  210. }
  211.  
  212. func (h *httpClient) formData(req *http.Request, parser ahelpers.Parser, timeout time.Duration, dest any) (*http.Response, error) {
  213.     req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
  214.     res, err := h.transport.RoundTrip(req)
  215.     if err != nil {
  216.         return nil, err
  217.     }
  218.  
  219.     h.transport.httpRequestDump(req)
  220.     h.transport.httpResponseDump(res)
  221.  
  222.     client := http.Client{Transport: h.transport, Timeout: timeout}
  223.     if res, err := client.Do(req); err != nil {
  224.         return res, err
  225.     }
  226.  
  227.     buffer, err := io.ReadAll(res.Body)
  228.     if err != nil {
  229.         return nil, err
  230.     }
  231.     defer res.Body.Close()
  232.  
  233.     res.Body = io.NopCloser(io.MultiReader(bytes.NewReader(buffer), res.Body))
  234.  
  235.     if !strings.Contains(string(buffer), "html") {
  236.         res.Body = io.NopCloser(res.Body)
  237.  
  238.         if err := parser.Decode(res.Body, dest); err != nil {
  239.             return nil, err
  240.         }
  241.         defer res.Body.Close()
  242.  
  243.         return res, nil
  244.     } else {
  245.         return res, errors.New("Output is not as expected")
  246.     }
  247. }
  248.  
  249. /**
  250. * ===========================================
  251. * HANDLER METHOD - RoundTripper
  252. * ===========================================
  253. **/
  254.  
  255. func (h *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
  256.     if h.Headers != nil {
  257.         for k, v := range h.Headers {
  258.             req.Header.Add(k, v)
  259.         }
  260.     }
  261.  
  262.     return http.DefaultTransport.RoundTrip(req)
  263. }
  264.  
  265. func (h *roundTripper) httpRequestDump(req *http.Request) {
  266.     dumpReq, err := httputil.DumpRequest(req, true)
  267.     if err != nil {
  268.         logrus.Errorf("RoundTripper httpRequestDump - httputil.DumpRequest: %v", err)
  269.         return
  270.     }
  271.  
  272.     fmt.Print("\n\n\n")
  273.     fmt.Println("=============== START DUMP HTTP REQUEST ================")
  274.     fmt.Print("\n")
  275.     fmt.Println(string(dumpReq))
  276.     fmt.Print("\n")
  277.     fmt.Println("=============== END DUMP HTTP REQUEST =================")
  278.     fmt.Print("\n\n\n")
  279. }
  280.  
  281. func (h *roundTripper) httpResponseDump(res *http.Response) {
  282.     dumpRes, err := httputil.DumpResponse(res, true)
  283.     if err != nil {
  284.         logrus.Errorf("RoundTripper httpResponseDump - httputil.DumpResponse: %v", err)
  285.         return
  286.     }
  287.  
  288.     fmt.Print("\n\n\n")
  289.     fmt.Println("=============== START DUMP HTTP RESPONSE ================")
  290.     fmt.Print("\n")
  291.     fmt.Println(string(dumpRes))
  292.     fmt.Print("\n")
  293.     fmt.Println("=============== END DUMP HTTP RESPONSE =================")
  294.     fmt.Print("\n\n\n")
  295. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement