github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/papi/property.go (about)

     1  package papi
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  
    10  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/edgegriderr"
    11  	validation "github.com/go-ozzo/ozzo-validation/v4"
    12  )
    13  
    14  type (
    15  	// Properties contains operations available on Property resource
    16  	// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#propertiesgroup
    17  	Properties interface {
    18  		GetProperties(ctx context.Context, r GetPropertiesRequest) (*GetPropertiesResponse, error)
    19  		CreateProperty(ctx context.Context, params CreatePropertyRequest) (*CreatePropertyResponse, error)
    20  		GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error)
    21  		RemoveProperty(ctx context.Context, params RemovePropertyRequest) (*RemovePropertyResponse, error)
    22  	}
    23  
    24  	// PropertyCloneFrom optionally identifies another property instance to clone when making a POST request to create a new property
    25  	PropertyCloneFrom struct {
    26  		CloneFromVersionEtag string `json:"cloneFromVersionEtag,omitempty"`
    27  		CopyHostnames        bool   `json:"copyHostnames,omitempty"`
    28  		PropertyID           string `json:"propertyId"`
    29  		Version              int    `json:"version"`
    30  	}
    31  
    32  	// Property contains configuration data to apply to edge content.
    33  	Property struct {
    34  		AccountID         string `json:"accountId"`
    35  		AssetID           string `json:"assetId"`
    36  		ContractID        string `json:"contractId"`
    37  		GroupID           string `json:"groupId"`
    38  		LatestVersion     int    `json:"latestVersion"`
    39  		Note              string `json:"note"`
    40  		ProductID         string `json:"productId"`
    41  		ProductionVersion *int   `json:"productionVersion,omitempty"`
    42  		PropertyID        string `json:"propertyId"`
    43  		PropertyName      string `json:"propertyName"`
    44  		RuleFormat        string `json:"ruleFormat"`
    45  		StagingVersion    *int   `json:"stagingVersion,omitempty"`
    46  	}
    47  
    48  	// PropertiesItems is an array of properties
    49  	PropertiesItems struct {
    50  		Items []*Property `json:"items"`
    51  	}
    52  
    53  	// GetPropertiesRequest is the argument for GetProperties
    54  	GetPropertiesRequest struct {
    55  		ContractID string
    56  		GroupID    string
    57  	}
    58  
    59  	// GetPropertiesResponse is the response for GetProperties
    60  	GetPropertiesResponse struct {
    61  		Properties PropertiesItems `json:"properties"`
    62  	}
    63  
    64  	// CreatePropertyRequest is passed to CreateProperty
    65  	CreatePropertyRequest struct {
    66  		ContractID string
    67  		GroupID    string
    68  		Property   PropertyCreate
    69  	}
    70  
    71  	// PropertyCreate represents a POST /property request body
    72  	PropertyCreate struct {
    73  		CloneFrom    *PropertyCloneFrom `json:"cloneFrom,omitempty"`
    74  		ProductID    string             `json:"productId"`
    75  		PropertyName string             `json:"propertyName"`
    76  		RuleFormat   string             `json:"ruleFormat,omitempty"`
    77  	}
    78  
    79  	// CreatePropertyResponse is returned by CreateProperty
    80  	CreatePropertyResponse struct {
    81  		Response
    82  		PropertyID   string
    83  		PropertyLink string `json:"propertyLink"`
    84  	}
    85  
    86  	// GetPropertyRequest is the argument for GetProperty
    87  	GetPropertyRequest struct {
    88  		ContractID string
    89  		GroupID    string
    90  		PropertyID string
    91  	}
    92  
    93  	// GetPropertyResponse is the response for GetProperty
    94  	GetPropertyResponse struct {
    95  		Response
    96  		Properties PropertiesItems `json:"properties"`
    97  		Property   *Property       `json:"-"`
    98  	}
    99  
   100  	// RemovePropertyRequest is the argument for RemoveProperty
   101  	RemovePropertyRequest struct {
   102  		PropertyID string
   103  		ContractID string
   104  		GroupID    string
   105  	}
   106  
   107  	// RemovePropertyResponse is the response for GetProperties
   108  	RemovePropertyResponse struct {
   109  		Message string `json:"message"`
   110  	}
   111  )
   112  
   113  // Validate validates GetPropertiesRequest
   114  func (v GetPropertiesRequest) Validate() error {
   115  	return validation.Errors{
   116  		"ContractID": validation.Validate(v.ContractID, validation.Required),
   117  		"GroupID":    validation.Validate(v.GroupID, validation.Required),
   118  	}.Filter()
   119  }
   120  
   121  // Validate validates CreatePropertyRequest
   122  func (v CreatePropertyRequest) Validate() error {
   123  	errs := validation.Errors{
   124  		"ContractID": validation.Validate(v.ContractID, validation.Required),
   125  		"GroupID":    validation.Validate(v.GroupID, validation.Required),
   126  		"Property":   validation.Validate(v.Property),
   127  	}
   128  	return edgegriderr.ParseValidationErrors(errs)
   129  }
   130  
   131  // Validate validates PropertyCreate
   132  func (p PropertyCreate) Validate() error {
   133  	return validation.Errors{
   134  		"ProductID":    validation.Validate(p.ProductID, validation.Required),
   135  		"PropertyName": validation.Validate(p.PropertyName, validation.Required),
   136  		"CloneFrom":    validation.Validate(p.CloneFrom),
   137  	}.Filter()
   138  }
   139  
   140  // Validate validates PropertyCloneFrom
   141  func (c PropertyCloneFrom) Validate() error {
   142  	return validation.Errors{
   143  		"PropertyID": validation.Validate(c.PropertyID),
   144  		"Version":    validation.Validate(c.Version),
   145  	}.Filter()
   146  }
   147  
   148  // Validate validates GetPropertyRequest
   149  func (v GetPropertyRequest) Validate() error {
   150  	return validation.Errors{
   151  		"PropertyID": validation.Validate(v.PropertyID, validation.Required),
   152  	}.Filter()
   153  }
   154  
   155  // Validate validates RemovePropertyRequest
   156  func (v RemovePropertyRequest) Validate() error {
   157  	return validation.Errors{
   158  		"PropertyID": validation.Validate(v.PropertyID, validation.Required),
   159  	}.Filter()
   160  }
   161  
   162  var (
   163  	// ErrGetProperties represents error when fetching properties fails
   164  	ErrGetProperties = errors.New("fetching properties")
   165  	// ErrGetProperty represents error when fetching property fails
   166  	ErrGetProperty = errors.New("fetching property")
   167  	// ErrCreateProperty represents error when creating property fails
   168  	ErrCreateProperty = errors.New("creating property")
   169  	// ErrRemoveProperty represents error when removing property fails
   170  	ErrRemoveProperty = errors.New("removing property")
   171  )
   172  
   173  func (p *papi) GetProperties(ctx context.Context, params GetPropertiesRequest) (*GetPropertiesResponse, error) {
   174  	if err := params.Validate(); err != nil {
   175  		return nil, fmt.Errorf("%s: %w: %s", ErrGetProperties, ErrStructValidation, err)
   176  	}
   177  
   178  	var rval GetPropertiesResponse
   179  
   180  	logger := p.Log(ctx)
   181  	logger.Debug("GetProperties")
   182  
   183  	uri := fmt.Sprintf(
   184  		"/papi/v1/properties?contractId=%s&groupId=%s",
   185  		params.ContractID,
   186  		params.GroupID)
   187  
   188  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   189  	if err != nil {
   190  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetProperties, err)
   191  	}
   192  
   193  	resp, err := p.Exec(req, &rval)
   194  	if err != nil {
   195  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetProperties, err)
   196  	}
   197  
   198  	if resp.StatusCode != http.StatusOK {
   199  		return nil, fmt.Errorf("%s: %w", ErrGetProperties, p.Error(resp))
   200  	}
   201  
   202  	return &rval, nil
   203  }
   204  
   205  func (p *papi) CreateProperty(ctx context.Context, params CreatePropertyRequest) (*CreatePropertyResponse, error) {
   206  	if err := params.Validate(); err != nil {
   207  		return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateProperty, ErrStructValidation, err)
   208  	}
   209  
   210  	logger := p.Log(ctx)
   211  	logger.Debug("CreateProperty")
   212  
   213  	uri := fmt.Sprintf(
   214  		"/papi/v1/properties?contractId=%s&groupId=%s",
   215  		params.ContractID,
   216  		params.GroupID)
   217  
   218  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil)
   219  	if err != nil {
   220  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateProperty, err)
   221  	}
   222  
   223  	var rval CreatePropertyResponse
   224  
   225  	resp, err := p.Exec(req, &rval, params.Property)
   226  	if err != nil {
   227  		return nil, fmt.Errorf("%w: request failed: %s", ErrCreateProperty, err)
   228  	}
   229  
   230  	if resp.StatusCode != http.StatusCreated {
   231  		return nil, fmt.Errorf("%s: %w", ErrCreateProperty, p.Error(resp))
   232  	}
   233  
   234  	id, err := ResponseLinkParse(rval.PropertyLink)
   235  	if err != nil {
   236  		return nil, fmt.Errorf("%s: %w: %s", ErrCreateProperty, ErrInvalidResponseLink, err)
   237  	}
   238  	rval.PropertyID = id
   239  
   240  	return &rval, nil
   241  }
   242  
   243  func (p *papi) GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error) {
   244  	if err := params.Validate(); err != nil {
   245  		return nil, fmt.Errorf("%s: %w: %s", ErrGetProperty, ErrStructValidation, err)
   246  	}
   247  
   248  	var rval GetPropertyResponse
   249  
   250  	logger := p.Log(ctx)
   251  	logger.Debug("GetProperty")
   252  
   253  	uri, err := url.Parse(fmt.Sprintf(
   254  		"/papi/v1/properties/%s",
   255  		params.PropertyID),
   256  	)
   257  	if err != nil {
   258  		return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetProperty, err)
   259  	}
   260  	q := uri.Query()
   261  	if params.GroupID != "" {
   262  		q.Add("groupId", params.GroupID)
   263  	}
   264  	if params.ContractID != "" {
   265  		q.Add("contractId", params.ContractID)
   266  	}
   267  	uri.RawQuery = q.Encode()
   268  
   269  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
   270  	if err != nil {
   271  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetProperty, err)
   272  	}
   273  
   274  	resp, err := p.Exec(req, &rval)
   275  	if err != nil {
   276  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetProperty, err)
   277  	}
   278  
   279  	if resp.StatusCode != http.StatusOK {
   280  		return nil, fmt.Errorf("%s: %w", ErrGetProperty, p.Error(resp))
   281  	}
   282  
   283  	if len(rval.Properties.Items) == 0 {
   284  		return nil, fmt.Errorf("%s: %w: PropertyID: %s", ErrGetProperty, ErrNotFound, params.PropertyID)
   285  	}
   286  	rval.Property = rval.Properties.Items[0]
   287  
   288  	return &rval, nil
   289  }
   290  
   291  func (p *papi) RemoveProperty(ctx context.Context, params RemovePropertyRequest) (*RemovePropertyResponse, error) {
   292  	if err := params.Validate(); err != nil {
   293  		return nil, fmt.Errorf("%s: %w: %s", ErrRemoveProperty, ErrStructValidation, err)
   294  	}
   295  
   296  	var rval RemovePropertyResponse
   297  
   298  	logger := p.Log(ctx)
   299  	logger.Debug("RemoveProperty")
   300  
   301  	uri, err := url.Parse(fmt.Sprintf(
   302  		"/papi/v1/properties/%s",
   303  		params.PropertyID),
   304  	)
   305  	if err != nil {
   306  		return nil, fmt.Errorf("%w: failed parse url: %s", ErrRemoveProperty, err)
   307  	}
   308  	q := uri.Query()
   309  	if params.GroupID != "" {
   310  		q.Add("groupId", params.GroupID)
   311  	}
   312  	if params.ContractID != "" {
   313  		q.Add("contractId", params.ContractID)
   314  	}
   315  	uri.RawQuery = q.Encode()
   316  
   317  	req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri.String(), nil)
   318  	if err != nil {
   319  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrRemoveProperty, err)
   320  	}
   321  
   322  	resp, err := p.Exec(req, &rval)
   323  	if err != nil {
   324  		return nil, fmt.Errorf("%w: request failed: %s", ErrRemoveProperty, err)
   325  	}
   326  
   327  	if resp.StatusCode != http.StatusOK {
   328  		return nil, fmt.Errorf("%s: %w", ErrRemoveProperty, p.Error(resp))
   329  	}
   330  
   331  	return &rval, nil
   332  }