fix: add getList with records wrapper + correct options format from browser capture

This commit is contained in:
2026-07-28 17:03:59 +08:00
parent 284a503541
commit 7190d93edf
7 changed files with 56 additions and 15 deletions
+1 -1
View File
@@ -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.getWithQuery(ctx, "/expense/orders/list", map[string]string{"options": "1"}, &raw); err != nil {
if err := b.client.getList(ctx, "/expense/orders/list", &raw); err != nil {
return nil, err
}
orders := make([]provider.Order, len(raw))
+17
View File
@@ -44,6 +44,23 @@ func (c *client) getWithQuery(ctx context.Context, path string, query map[string
return c.do(ctx, "GET", path, nil, result, query)
}
// getList sends a GET request to a Rainyun list endpoint and extracts the "records" field.
func (c *client) getList(ctx context.Context, path string, result any) error {
var wrapper listResponse
if err := c.do(ctx, "GET", path, nil, &wrapper, listOptions()); err != nil {
return err
}
// Unmarshal the records array into the result
recordsJSON, err := json.Marshal(wrapper.Records)
if err != nil {
return fmt.Errorf("marshal records: %w", err)
}
if err := json.Unmarshal(recordsJSON, result); err != nil {
return fmt.Errorf("unmarshal records: %w", err)
}
return nil
}
func (c *client) post(ctx context.Context, path string, body, result any) error {
return c.do(ctx, "POST", path, body, result, nil)
}
+1 -1
View File
@@ -20,7 +20,7 @@ type rainyunDomain struct {
func (d *DomainService) List(ctx context.Context) ([]provider.Domain, error) {
var raw []rainyunDomain
if err := d.client.getWithQuery(ctx, "/product/domain/", map[string]string{"options": "1"}, &raw); err != nil {
if err := d.client.getList(ctx, "/product/domain/", &raw); err != nil {
return nil, err
}
domains := make([]provider.Domain, len(raw))
+21
View File
@@ -0,0 +1,21 @@
package rainyun
// listOptions returns the standard pagination query for Rainyun list endpoints.
// Format verified via browser DevTools capture of the Rainyun web console:
//
// https://api.v2.rainyun.com/product/rcs/?options={url-encoded JSON}
//
// The decoded JSON is: {"columnFilters":{},"sort":[],"page":1,"perPage":20}
func listOptions() map[string]string {
return map[string]string{
"options": `{"columnFilters":{},"sort":[],"page":1,"perPage":50}`,
}
}
// listResponse is the JSON envelope returned by Rainyun list endpoints.
// The API wraps data in {"code":0,"data":{"records":[...],"totalRecords":N}}.
// Our client extracts apiResp.Data ({"records":[...]}), then we unmarshal into this.
type listResponse struct {
Records []any `json:"records"`
TotalRecords int `json:"totalRecords"`
}
+1 -1
View File
@@ -29,7 +29,7 @@ type rainyunServer struct {
func (s *ServerService) List(ctx context.Context) ([]provider.Server, error) {
var raw []rainyunServer
if err := s.client.getWithQuery(ctx, "/product/rcs/", map[string]string{"options": "1"}, &raw); err != nil {
if err := s.client.getList(ctx, "/product/rcs/", &raw); err != nil {
return nil, err
}
servers := make([]provider.Server, len(raw))
+14 -11
View File
@@ -15,18 +15,21 @@ func TestServerList(t *testing.T) {
}
resp := map[string]any{
"code": 0,
"data": []map[string]any{
{
"id": 12001,
"name": "web-server",
"status": "running",
"ip": "1.2.3.4",
"vcpu": 2,
"memory": 4096,
"disk": 50,
"os": "Ubuntu 22.04",
"expire_date": "2026-08-15",
"data": map[string]any{
"records": []map[string]any{
{
"id": 12001,
"name": "web-server",
"status": "running",
"ip": "1.2.3.4",
"vcpu": 2,
"memory": 4096,
"disk": 50,
"os": "Ubuntu 22.04",
"expire_date": "2026-08-15",
},
},
"totalRecords": 1,
},
}
json.NewEncoder(w).Encode(resp)
+1 -1
View File
@@ -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.getWithQuery(ctx, "/product/ros/instance", map[string]string{"options": "1"}, &raw); err != nil {
if err := s.client.getList(ctx, "/product/ros/instance", &raw); err != nil {
return nil, err
}
instances := make([]provider.StorageInstance, len(raw))