package gonexapp import ( "bytes" "encoding/json" "fmt" "io" "net/http" "strings" ) // OCSClient performs AppAPI-authenticated OCS requests with format=json. type OCSClient struct { Cred Credentials Client *http.Client } func (c OCSClient) httpClient() *http.Client { if c.Client != nil { return c.Client } return http.DefaultClient } // URL builds an OCS URL under /ocs/v2.php with format=json. func (c OCSClient) URL(path string) string { base := strings.TrimRight(c.Cred.BaseURL, "/") path = strings.TrimPrefix(path, "/") return base + "/ocs/v2.php/" + path + "?format=json" } // Call performs method against path with an optional JSON body and returns the response body // after verifying it is valid JSON. Non-2xx responses return an error including the status. func (c OCSClient) Call(method, path string, body []byte) ([]byte, error) { var reader io.Reader if len(body) > 0 { reader = bytes.NewReader(body) } req, err := http.NewRequest(method, c.URL(path), reader) if err != nil { return nil, err } if len(body) > 0 { req.Header.Set("Content-Type", "application/json") } for k, vs := range c.Cred.AuthHeaders() { for _, v := range vs { req.Header.Set(k, v) } } res, err := c.httpClient().Do(req) if err != nil { return nil, err } defer res.Body.Close() raw, err := io.ReadAll(res.Body) if err != nil { return nil, err } if res.StatusCode >= 300 { return nil, fmt.Errorf("ocs %s %s: %s", method, path, res.Status) } if !json.Valid(raw) { return nil, fmt.Errorf("ocs %s %s: response is not JSON", method, path) } return raw, nil }