package api import ( "bytes" "encoding/json" "errors" "fmt" "io" "mime/multipart" "net/http" "net/url" "git.agecem.com/agecem/agecem-org/config" "git.agecem.com/agecem/agecem-org/models" "github.com/spf13/viper" ) type API struct { Protocol string Host string Port int Opts APIOptions } type APIOptions struct { KeyAuth bool Key string BasicAuth bool Username string Password string } // NewApiClientFromViper returns a pointer to a new API object, // provided the configuration options are managed by // https://git.agecem.com/agecem/agecem-org/config func NewApiClientFromViper() (*API, error) { var config config.Config if err := viper.Unmarshal(&config); err != nil { return nil, err } api, err := New(config.Server.Api.Protocol, config.Server.Api.Host, config.Server.Api.Port, APIOptions{ KeyAuth: config.Server.Api.Auth, Key: config.Server.Api.Key, }) if err != nil { return api, err } return api, nil } func New(protocol, host string, port int, opts APIOptions) (*API, error) { api := API{ Protocol: protocol, Host: host, Port: port, Opts: opts, } return &api, nil } // Call returns a []byte representing a response body. // Can be used for GET or DELETE methods func (a *API) Call(method, route string) ([]byte, error) { endpoint := fmt.Sprintf("%s://%s:%d", a.Protocol, a.Host, a.Port, ) prerequest := fmt.Sprintf("%s%s", endpoint, route) request, err := url.QueryUnescape(prerequest) if err != nil { return nil, err } switch method { case http.MethodGet: // Create client client := &http.Client{} // Create request request, err := http.NewRequest(http.MethodGet, request, nil) if err != nil { return nil, err } if a.Opts.KeyAuth { request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Opts.Key)) } // Fetch Request response, err := client.Do(request) if err != nil { return nil, err } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { return nil, err } return body, nil case http.MethodDelete: // Create client client := &http.Client{} // Create request req, err := http.NewRequest(http.MethodDelete, request, nil) if err != nil { return nil, err } if a.Opts.KeyAuth { req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Opts.Key)) } // Fetch Request resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // Read Response Body respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, err } return respBody, nil } //return nil, errors.New(fmt.Sprintf("method must be 'GET' or 'DELETE', got '%s'", method)) return nil, errors.New(fmt.Sprintf("method must be 'GET' or 'DELETE', got '%s'", method)) } func (a *API) UploadDocument(bucket string, file_header *multipart.FileHeader) (models.V1DocumentCreateResponse, error) { var response models.V1DocumentCreateResponse endpoint := fmt.Sprintf("%s://%s:%d", a.Protocol, a.Host, a.Port, ) current_url := fmt.Sprintf("%s/v1/bucket/%s", endpoint, bucket) // Create a new multipart writer body := &bytes.Buffer{} writer := multipart.NewWriter(body) // Add the file to the request file, err := file_header.Open() if err != nil { return response, fmt.Errorf("UploadDocument#file_header.Open: %s", err) } defer file.Close() filename_processed, err := url.QueryUnescape(file_header.Filename) if err != nil { return response, fmt.Errorf("UploadDocument#url.QueryUnescape: %s", err) } part, err := writer.CreateFormFile("document", filename_processed) if err != nil { return response, fmt.Errorf("UploadDocument#writer.CreateFormFile: %s", err) } _, err = io.Copy(part, file) if err != nil { return response, fmt.Errorf("UploadDocument#io.Copy: %s", err) } err = writer.Close() if err != nil { return response, fmt.Errorf("UploadDocument#writer.Close: %s", err) } // Create a new HTTP request with the multipart body req, err := http.NewRequest(http.MethodPost, current_url, body) if err != nil { return response, fmt.Errorf("UploadDocument#http.NewRequest: %s", err) } req.Header.Set("Content-Type", writer.FormDataContentType()) if a.Opts.KeyAuth { req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", a.Opts.Key)) } // Send the HTTP request client := &http.Client{} resp, err := client.Do(req) if err != nil { return response, fmt.Errorf("UploadDocument#client.Do: %s", err) } defer resp.Body.Close() err = json.NewDecoder(resp.Body).Decode(&response) return response, err } // CallWithData takes data and returns a string representing a response body. // Can be used for POST or PUT methods func (a *API) CallWithData(method, route string, data []byte) (string, error) { endpoint := fmt.Sprintf("%s://%s:%d", a.Protocol, a.Host, a.Port, ) request := fmt.Sprintf("%s%s", endpoint, route) switch method { case http.MethodPost: // initialize http client client := &http.Client{} // set the HTTP method, url, and request body req, err := http.NewRequest(http.MethodPost, request, bytes.NewBuffer(data)) if err != nil { return "", err } if a.Opts.KeyAuth { req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Opts.Key)) } // set the request header Content-Type for json req.Header.Set("Content-Type", "application/json; charset=utf-8") resp, err := client.Do(req) if err != nil { return "", err } var res map[string]interface{} json.NewDecoder(resp.Body).Decode(&res) return fmt.Sprintf("%s\n", res["message"]), nil /* case http.MethodPut: // initialize http client client := &http.Client{} // set the HTTP method, url, and request body req, err := http.NewRequest(http.MethodPut, request, bytes.NewBuffer(data)) if err != nil { return "", err } if a.Opts.KeyAuth { req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Opts.Key)) } // set the request header Content-Type for json //req.Header.Set("Content-Type", "application/json; charset=utf-8") resp, err := client.Do(req) if err != nil { return "", err } var res map[string]interface{} json.NewDecoder(resp.Body).Decode(&res) return fmt.Sprintf("%s\n", res["message"]), nil */ } //return "", errors.New(fmt.Sprintf("method must be 'POST' or 'PUT', got '%s'", method)) return "", errors.New(fmt.Sprintf("method must be 'POST', got '%s'", method)) } func (a *API) ListBuckets() (models.V1BucketListResponse, error) { var response models.V1BucketListResponse result, err := a.Call(http.MethodGet, "/v1/bucket") if err != nil { return response, err } if err = json.Unmarshal(result, &response); err != nil { return response, err } return response, nil }