Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

120 linhas
3.2 KiB

  1. package helpers
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "net/http/cookiejar"
  9. "strings"
  10. "time"
  11. "github.com/QuantumNous/new-api/common"
  12. )
  13. type APIClient struct {
  14. BaseURL string
  15. UserID int
  16. client *http.Client
  17. }
  18. func NewAPIClient(baseURL string) (*APIClient, error) {
  19. jar, err := cookiejar.New(nil)
  20. if err != nil {
  21. return nil, fmt.Errorf("create cookie jar: %w", err)
  22. }
  23. return &APIClient{
  24. BaseURL: strings.TrimRight(baseURL, "/"),
  25. client: &http.Client{
  26. Jar: jar,
  27. Timeout: 15 * time.Second,
  28. },
  29. }, nil
  30. }
  31. func (c *APIClient) DoJSON(method, path string, requestBody any, expectedStatus int, responseBody any) error {
  32. return c.DoJSONWithHeaders(method, path, requestBody, expectedStatus, nil, responseBody)
  33. }
  34. func (c *APIClient) DoJSONWithHeaders(method, path string, requestBody any, expectedStatus int, headers map[string]string, responseBody any) error {
  35. var bodyReader io.Reader
  36. var requestDump string
  37. if requestBody != nil {
  38. data, err := common.Marshal(requestBody)
  39. if err != nil {
  40. return fmt.Errorf("marshal request body for %s %s: %w", method, path, err)
  41. }
  42. bodyReader = bytes.NewReader(data)
  43. requestDump = string(data)
  44. }
  45. req, err := http.NewRequest(method, c.BaseURL+path, bodyReader)
  46. if err != nil {
  47. return fmt.Errorf("create request %s %s: %w", method, path, err)
  48. }
  49. req.Header.Set("Accept", "application/json")
  50. if requestBody != nil {
  51. req.Header.Set("Content-Type", "application/json")
  52. }
  53. if c.UserID != 0 {
  54. req.Header.Set("New-Api-User", fmt.Sprintf("%d", c.UserID))
  55. }
  56. for key, value := range headers {
  57. req.Header.Set(key, value)
  58. }
  59. resp, err := c.client.Do(req)
  60. if err != nil {
  61. return fmt.Errorf("do request %s %s: %w", method, path, err)
  62. }
  63. defer resp.Body.Close()
  64. respData, err := io.ReadAll(resp.Body)
  65. if err != nil {
  66. return fmt.Errorf("read response %s %s: %w", method, path, err)
  67. }
  68. if resp.StatusCode != expectedStatus {
  69. return fmt.Errorf(
  70. "%s %s: expected status %d, got %d, request=%s, response=%s",
  71. method, path, expectedStatus, resp.StatusCode, requestDump, string(respData),
  72. )
  73. }
  74. if responseBody == nil || len(respData) == 0 {
  75. return nil
  76. }
  77. if err := common.Unmarshal(respData, responseBody); err != nil {
  78. return fmt.Errorf(
  79. "unmarshal response for %s %s: %w, raw=%s",
  80. method, path, err, string(respData),
  81. )
  82. }
  83. return nil
  84. }
  85. func (c *APIClient) GetJSON(path string, expectedStatus int, responseBody any) error {
  86. return c.DoJSON(http.MethodGet, path, nil, expectedStatus, responseBody)
  87. }
  88. func (c *APIClient) PostJSON(path string, requestBody any, expectedStatus int, responseBody any) error {
  89. return c.DoJSON(http.MethodPost, path, requestBody, expectedStatus, responseBody)
  90. }
  91. func (c *APIClient) PutJSON(path string, requestBody any, expectedStatus int, responseBody any) error {
  92. return c.DoJSON(http.MethodPut, path, requestBody, expectedStatus, responseBody)
  93. }
  94. func (c *APIClient) DeleteJSON(path string, expectedStatus int, responseBody any) error {
  95. return c.DoJSON(http.MethodDelete, path, nil, expectedStatus, responseBody)
  96. }
  97. type Envelope struct {
  98. Success bool `json:"success"`
  99. Message string `json:"message,omitempty"`
  100. Error string `json:"error,omitempty"`
  101. Data json.RawMessage `json:"data,omitempty"`
  102. }