-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathclient.go
More file actions
129 lines (111 loc) · 3.74 KB
/
client.go
File metadata and controls
129 lines (111 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
Copyright 2025 The Antfly Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//go:generate go tool oapi-codegen --config=cfg.yaml ../../openapi.yaml
package client
import (
"context"
"encoding/base64"
"fmt"
"io"
"net/http"
"github.com/antflydb/antfly/pkg/client/oapi"
"github.com/antflydb/antfly/pkg/libaf/json"
)
// AntflyClient is a client for interacting with the Antfly API
type AntflyClient struct {
client *oapi.Client
}
// NewAntflyClient creates a new Antfly client with an HTTP client.
func NewAntflyClient(baseURL string, httpClient *http.Client) (*AntflyClient, error) {
client, err := oapi.NewClient(baseURL, oapi.WithHTTPClient(httpClient))
if err != nil {
return nil, err
}
return &AntflyClient{
client: client,
}, nil
}
// NewAntflyClientWithOptions creates a new Antfly client with variadic options.
// Use with WithBasicAuth, WithApiKey, or WithBearerToken for authentication.
func NewAntflyClientWithOptions(baseURL string, opts ...oapi.ClientOption) (*AntflyClient, error) {
client, err := oapi.NewClient(baseURL, opts...)
if err != nil {
return nil, err
}
return &AntflyClient{
client: client,
}, nil
}
// WithBasicAuth returns a RequestEditorFn that adds HTTP Basic Authentication.
func WithBasicAuth(username, password string) oapi.RequestEditorFn {
encoded := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return func(_ context.Context, req *http.Request) error {
req.Header.Set("Authorization", "Basic "+encoded)
return nil
}
}
// WithApiKey returns a RequestEditorFn that adds API Key authentication.
// The credential is sent as: Authorization: ApiKey base64(keyID:keySecret)
func WithApiKey(keyID, keySecret string) oapi.RequestEditorFn {
encoded := base64.StdEncoding.EncodeToString([]byte(keyID + ":" + keySecret))
return func(_ context.Context, req *http.Request) error {
req.Header.Set("Authorization", "ApiKey "+encoded)
return nil
}
}
// WithBearerToken returns a RequestEditorFn that adds Bearer token authentication.
// The token should be base64(keyID:keySecret) for Antfly API keys, or an opaque token
// from a proxy.
func WithBearerToken(token string) oapi.RequestEditorFn {
return func(_ context.Context, req *http.Request) error {
req.Header.Set("Authorization", "Bearer "+token)
return nil
}
}
// APIError represents a structured error response from the Antfly API.
// Callers can use errors.As to extract it:
//
// var apiErr *client.APIError
// if errors.As(err, &apiErr) {
// fmt.Println(apiErr.StatusCode, apiErr.Message)
// }
type APIError struct {
// StatusCode is the HTTP status code returned by the server.
StatusCode int
// Message is the error message from the server.
Message string
}
func (e *APIError) Error() string {
return e.Message
}
func readErrorResponse(resp *http.Response) error {
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("reading http response: %w", err)
}
// Try to parse as JSON error response
var errResp struct {
Error string `json:"error"`
}
if err := json.Unmarshal(respBody, &errResp); err == nil && errResp.Error != "" {
return &APIError{
StatusCode: resp.StatusCode,
Message: errResp.Error,
}
}
// Fallback for non-JSON responses
return &APIError{
StatusCode: resp.StatusCode,
Message: string(respBody),
}
}