package mongodbAPI import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" "strings" "github.com/pkg/errors" ) const ( dbapi = "https://dbapi.nsi.rackspace.com" stagingDBapi = "https://staging.nsi.rackspace.com" sensitiveHeaders = "apikey,X-Auth" ) type ( // Client type is the initialized type returned from the New function // and is used as the pointer receiver in method calls. Client struct { headers map[string]string db string dbURL string } // Sort type defines the parameters required for pass to the MongoAPI for // each field that you are sorting by. Sort map[string]struct { IsInt bool `json:"int"` Reverse bool `json:"reverse"` } // Auth is a signature type to represent the // types of authentication available. Auth func(c *Client) ) // WithToken is an auth method that takes a core token // for authentication // nolint:unused func WithToken(s string) Auth { return func(c *Client) { c.headers = map[string]string{ "Content-Type": "application/json", "X-Auth": s, } } } // WithAPIKey is an auth method that takes an API key // for authentication // nolint:unused func WithAPIKey(s string) Auth { return func(c *Client) { c.headers = map[string]string{ "Content-Type": "application/json", "apikey": s, } } } // WithIdentity is an auth method that takes a Rackspace identity // token for authentication // nolint:unused func WithIdentity(s string) Auth { return func(c *Client) { c.headers = map[string]string{ "Content-Type": "application/json", "X-Auth-Token": s, } } } // New function will create a new client for the mongo API. This function // will initialize the client with the selected database, authentication method, // and database hostname. The response will be an initialized client. func New(auth Auth, db string, staging bool) *Client { var c = &Client{ db: db, dbURL: func() string { if staging { return fmt.Sprintf("%v/%v/", stagingDBapi, db) } return fmt.Sprintf("%v/%v/", dbapi, db) }(), } // Apply authentication auth(c) return c } func (d *Client) post(payload []byte, path string) ([]byte, error) { if strings.HasPrefix(path, "/") { path = strings.TrimLeft(path, "/") } queryURL := d.dbURL + path req, err := http.NewRequest(http.MethodPost, queryURL, bytes.NewBuffer(payload)) if err != nil { return nil, err } for key, value := range d.headers { req.Header.Add(key, value) } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer func() { if defErr := resp.Body.Close(); defErr != nil { err = errors.Wrap(defErr, "defer resp.Body.Close") } }() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } if resp.StatusCode != 200 { errStr := fmt.Sprintf("mongodbAPI:post(url: %v):code %v:", queryURL, resp.StatusCode) apiErr := struct { Error string `json:"error"` }{} if err := json.NewDecoder(bytes.NewReader(body)).Decode(&apiErr); err != nil { return nil, fmt.Errorf("%v msg: %v", errStr, string(body)) } return nil, fmt.Errorf("%v msg: %v", errStr, apiErr.Error) } return body, nil } // DB method is an exported call to return the current selected // database func (d *Client) DB() string { return d.db } // DBURL method is an exported call to return the selected // mongo hostname. func (d *Client) DBURL() string { return d.dbURL } // Headers method will return the current configured HTTP headers // we send to each mongoAPI call. func (d *Client) Headers() map[string]string { h := make(map[string]string) for header, content := range d.headers { if strings.Contains(sensitiveHeaders, header) { h[header] = "REDACTED" continue } h[header] = content } return h }