fix: query params support + remove duplicate response wrappers + fix tests
This commit is contained in:
@@ -21,7 +21,7 @@ func (b *BillingService) Orders(ctx context.Context) ([]provider.Order, error) {
|
||||
CreateDate string `json:"create_date"`
|
||||
}
|
||||
var raw []rainyunOrder
|
||||
if err := b.client.get(ctx, "/expense/orders/list", &raw); err != nil {
|
||||
if err := b.client.getWithQuery(ctx, "/expense/orders/list", map[string]string{"options": "1"}, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orders := make([]provider.Order, len(raw))
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -36,23 +37,35 @@ type apiResponse struct {
|
||||
}
|
||||
|
||||
func (c *client) get(ctx context.Context, path string, result any) error {
|
||||
return c.do(ctx, "GET", path, nil, result)
|
||||
return c.do(ctx, "GET", path, nil, result, nil)
|
||||
}
|
||||
|
||||
func (c *client) getWithQuery(ctx context.Context, path string, query map[string]string, result any) error {
|
||||
return c.do(ctx, "GET", path, nil, result, query)
|
||||
}
|
||||
|
||||
func (c *client) post(ctx context.Context, path string, body, result any) error {
|
||||
return c.do(ctx, "POST", path, body, result)
|
||||
return c.do(ctx, "POST", path, body, result, nil)
|
||||
}
|
||||
|
||||
func (c *client) patch(ctx context.Context, path string, body, result any) error {
|
||||
return c.do(ctx, "PATCH", path, body, result)
|
||||
return c.do(ctx, "PATCH", path, body, result, nil)
|
||||
}
|
||||
|
||||
func (c *client) delete(ctx context.Context, path string, result any) error {
|
||||
return c.do(ctx, "DELETE", path, nil, result)
|
||||
return c.do(ctx, "DELETE", path, nil, result, nil)
|
||||
}
|
||||
|
||||
func (c *client) do(ctx context.Context, method, path string, body, result any) error {
|
||||
url := c.baseURL + path
|
||||
func (c *client) do(ctx context.Context, method, path string, body, result any, query map[string]string) error {
|
||||
u := c.baseURL + path
|
||||
|
||||
if len(query) > 0 {
|
||||
params := url.Values{}
|
||||
for k, v := range query {
|
||||
params.Set(k, v)
|
||||
}
|
||||
u += "?" + params.Encode()
|
||||
}
|
||||
|
||||
var bodyReader io.Reader
|
||||
if body != nil {
|
||||
@@ -63,7 +76,7 @@ func (c *client) do(ctx context.Context, method, path string, body, result any)
|
||||
bodyReader = bytes.NewReader(b)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, url, bodyReader)
|
||||
req, err := http.NewRequestWithContext(ctx, method, u, bodyReader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create request: %w", err)
|
||||
}
|
||||
@@ -88,7 +101,7 @@ func (c *client) do(ctx context.Context, method, path string, body, result any)
|
||||
return &APIError{
|
||||
StatusCode: resp.StatusCode,
|
||||
Method: method,
|
||||
URL: url,
|
||||
URL: u,
|
||||
Body: respBody,
|
||||
APICode: apiResp.Code,
|
||||
APIMsg: apiResp.Msg,
|
||||
@@ -98,14 +111,14 @@ func (c *client) do(ctx context.Context, method, path string, body, result any)
|
||||
return &APIError{
|
||||
StatusCode: resp.StatusCode,
|
||||
Method: method,
|
||||
URL: url,
|
||||
URL: u,
|
||||
Body: respBody,
|
||||
}
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
if err := json.Unmarshal(respBody, result); err != nil {
|
||||
return fmt.Errorf("unmarshal response: %w", err)
|
||||
if result != nil && apiResp.Data != nil {
|
||||
if err := json.Unmarshal(apiResp.Data, result); err != nil {
|
||||
return fmt.Errorf("unmarshal data: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -18,11 +18,8 @@ func TestClientAuthHeader(t *testing.T) {
|
||||
|
||||
c := newClient(srv.URL, "sk-test")
|
||||
var result struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := c.get(context.Background(), "/test", &result); err != nil {
|
||||
t.Fatalf("get() error: %v", err)
|
||||
@@ -30,8 +27,8 @@ func TestClientAuthHeader(t *testing.T) {
|
||||
if gotKey != "sk-test" {
|
||||
t.Errorf("X-Api-Key = %q, want %q", gotKey, "sk-test")
|
||||
}
|
||||
if result.Data.Name != "test" {
|
||||
t.Errorf("Data.Name = %q, want %q", result.Data.Name, "test")
|
||||
if result.Name != "test" {
|
||||
t.Errorf("Name = %q, want %q", result.Name, "test")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ type rainyunDomain struct {
|
||||
|
||||
func (d *DomainService) List(ctx context.Context) ([]provider.Domain, error) {
|
||||
var raw []rainyunDomain
|
||||
if err := d.client.get(ctx, "/product/domain/", &raw); err != nil {
|
||||
if err := d.client.getWithQuery(ctx, "/product/domain/", map[string]string{"options": "1"}, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domains := make([]provider.Domain, len(raw))
|
||||
|
||||
@@ -27,43 +27,25 @@ type rainyunServer struct {
|
||||
ExpireDate string `json:"expire_date"`
|
||||
}
|
||||
|
||||
// Response wrappers — the client unmarshals the full API envelope (code + data).
|
||||
type serverListResponse struct {
|
||||
Code int `json:"code"`
|
||||
Data []rainyunServer `json:"data"`
|
||||
}
|
||||
|
||||
type serverGetResponse struct {
|
||||
Code int `json:"code"`
|
||||
Data rainyunServer `json:"data"`
|
||||
}
|
||||
|
||||
type vncResponse struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
VNCURL string `json:"vnc_url"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (s *ServerService) List(ctx context.Context) ([]provider.Server, error) {
|
||||
var resp serverListResponse
|
||||
if err := s.client.get(ctx, "/product/rcs/", &resp); err != nil {
|
||||
var raw []rainyunServer
|
||||
if err := s.client.getWithQuery(ctx, "/product/rcs/", map[string]string{"options": "1"}, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers := make([]provider.Server, len(resp.Data))
|
||||
for i, r := range resp.Data {
|
||||
servers := make([]provider.Server, len(raw))
|
||||
for i, r := range raw {
|
||||
servers[i] = toServer(r)
|
||||
}
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func (s *ServerService) Get(ctx context.Context, id string) (*provider.Server, error) {
|
||||
var resp serverGetResponse
|
||||
var raw rainyunServer
|
||||
path := fmt.Sprintf("/product/rcs/%s/", id)
|
||||
if err := s.client.get(ctx, path, &resp); err != nil {
|
||||
if err := s.client.get(ctx, path, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sv := toServer(resp.Data)
|
||||
sv := toServer(raw)
|
||||
return &sv, nil
|
||||
}
|
||||
|
||||
@@ -89,11 +71,13 @@ func (s *ServerService) ResetPassword(ctx context.Context, id string) error {
|
||||
}
|
||||
|
||||
func (s *ServerService) GetVNC(ctx context.Context, id string) (string, error) {
|
||||
var resp vncResponse
|
||||
var resp struct {
|
||||
VNCURL string `json:"vnc_url"`
|
||||
}
|
||||
if err := s.client.get(ctx, fmt.Sprintf("/product/rcs/%s/vnc", id), &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.Data.VNCURL, nil
|
||||
return resp.VNCURL, nil
|
||||
}
|
||||
|
||||
func (s *ServerService) Upgrade(ctx context.Context, id, plan string) error {
|
||||
|
||||
@@ -17,7 +17,7 @@ func (s *StorageService) List(ctx context.Context) ([]provider.StorageInstance,
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := s.client.get(ctx, "/product/ros/instance", &raw); err != nil {
|
||||
if err := s.client.getWithQuery(ctx, "/product/ros/instance", map[string]string{"options": "1"}, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instances := make([]provider.StorageInstance, len(raw))
|
||||
|
||||
Reference in New Issue
Block a user