package photos import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" ) type BulkAssetResult struct { ID string `json:"id"` Success bool `json:"success"` Error string `json:"error,omitempty"` } type createAlbumPayload struct { AlbumName string `json:"albumName"` Description string `json:"description,omitempty"` AssetIDs []string `json:"assetIds,omitempty"` } type updateAlbumPayload struct { AlbumName *string `json:"albumName,omitempty"` Description *string `json:"description,omitempty"` } type bulkIDsPayload struct { IDs []string `json:"ids"` } func (c *Client) GetAlbum(ctx context.Context, apiKey, albumID string) (Album, error) { url := fmt.Sprintf("%s/albums/%s?withoutAssets=true", c.baseURL, albumID) var album Album if err := c.doJSON(ctx, http.MethodGet, url, apiKey, nil, &album, "get album", http.StatusOK); err != nil { return Album{}, err } return album, nil } func (c *Client) CreateAlbum(ctx context.Context, apiKey, name, description string, assetIDs []string) (Album, error) { payload := createAlbumPayload{ AlbumName: name, Description: description, AssetIDs: assetIDs, } var album Album if err := c.doJSON(ctx, http.MethodPost, c.baseURL+"/albums", apiKey, payload, &album, "create album", http.StatusCreated); err != nil { return Album{}, err } return album, nil } func (c *Client) UpdateAlbum(ctx context.Context, apiKey, albumID string, name, description *string) (Album, error) { payload := updateAlbumPayload{ AlbumName: name, Description: description, } url := fmt.Sprintf("%s/albums/%s", c.baseURL, albumID) var album Album if err := c.doJSON(ctx, http.MethodPatch, url, apiKey, payload, &album, "update album", http.StatusOK); err != nil { return Album{}, err } return album, nil } func (c *Client) DeleteAlbum(ctx context.Context, apiKey, albumID string) error { url := fmt.Sprintf("%s/albums/%s", c.baseURL, albumID) return c.doJSON(ctx, http.MethodDelete, url, apiKey, nil, nil, "delete album", http.StatusOK, http.StatusNoContent) } func (c *Client) AddAlbumAssets(ctx context.Context, apiKey, albumID string, assetIDs []string) ([]BulkAssetResult, error) { url := fmt.Sprintf("%s/albums/%s/assets", c.baseURL, albumID) var results []BulkAssetResult if err := c.doJSON(ctx, http.MethodPut, url, apiKey, bulkIDsPayload{IDs: assetIDs}, &results, "add album assets", http.StatusOK); err != nil { return nil, err } return results, nil } func (c *Client) RemoveAlbumAssets(ctx context.Context, apiKey, albumID string, assetIDs []string) ([]BulkAssetResult, error) { url := fmt.Sprintf("%s/albums/%s/assets", c.baseURL, albumID) var results []BulkAssetResult if err := c.doJSON(ctx, http.MethodDelete, url, apiKey, bulkIDsPayload{IDs: assetIDs}, &results, "remove album assets", http.StatusOK); err != nil { return nil, err } return results, nil } func (c *Client) doJSON(ctx context.Context, method, url, apiKey string, reqBody any, dest any, operation string, okStatuses ...int) error { var body io.Reader if reqBody != nil { data, err := json.Marshal(reqBody) if err != nil { return err } body = bytes.NewReader(data) } req, err := http.NewRequestWithContext(ctx, method, url, body) if err != nil { return err } req.Header.Set("x-api-key", apiKey) if reqBody != nil { req.Header.Set("Content-Type", "application/json") } resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() for _, status := range okStatuses { if resp.StatusCode == status { if dest != nil { if err := json.NewDecoder(resp.Body).Decode(dest); err != nil { return err } } return nil } } io.Copy(io.Discard, resp.Body) return &HTTPStatusError{Operation: operation, StatusCode: resp.StatusCode} }