github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/papi/include.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/v8/pkg/edgegriderr" 11 12 validation "github.com/go-ozzo/ozzo-validation/v4" 13 ) 14 15 type ( 16 // Includes contains operations available on Include resource 17 Includes interface { 18 // ListIncludes lists Includes available for the current contract and group 19 // 20 // See: https://techdocs.akamai.com/property-mgr/reference/get-includes 21 ListIncludes(context.Context, ListIncludesRequest) (*ListIncludesResponse, error) 22 23 // ListIncludeParents lists parents of a specific Include 24 // 25 // See: https://techdocs.akamai.com/property-mgr/reference/get-include-parents 26 ListIncludeParents(context.Context, ListIncludeParentsRequest) (*ListIncludeParentsResponse, error) 27 28 // GetInclude gets information about a specific Include 29 // 30 // See: https://techdocs.akamai.com/property-mgr/reference/get-include 31 GetInclude(context.Context, GetIncludeRequest) (*GetIncludeResponse, error) 32 33 // CreateInclude creates a new Include 34 // 35 // See: https://techdocs.akamai.com/property-mgr/reference/post-includes 36 CreateInclude(context.Context, CreateIncludeRequest) (*CreateIncludeResponse, error) 37 38 // DeleteInclude deletes an Include 39 // 40 // See: https://techdocs.akamai.com/property-mgr/reference/delete-include 41 DeleteInclude(context.Context, DeleteIncludeRequest) (*DeleteIncludeResponse, error) 42 } 43 44 // ListIncludesRequest contains parameters used to list includes 45 ListIncludesRequest struct { 46 ContractID string 47 GroupID string 48 } 49 50 // ListIncludesResponse represents a response object returned by ListIncludes 51 ListIncludesResponse struct { 52 Includes IncludeItems `json:"includes"` 53 } 54 55 // ListIncludeParentsRequest contains parameters used to list parents of an include 56 ListIncludeParentsRequest struct { 57 ContractID string 58 GroupID string 59 IncludeID string 60 } 61 62 // ListIncludeParentsResponse represents a response object returned by ListIncludeParents 63 ListIncludeParentsResponse struct { 64 Properties ParentPropertyItems `json:"properties"` 65 } 66 67 // GetIncludeRequest contains parameters used to fetch an include 68 GetIncludeRequest struct { 69 ContractID string 70 GroupID string 71 IncludeID string 72 } 73 74 // GetIncludeResponse represents a response object returned by GetInclude 75 GetIncludeResponse struct { 76 Includes IncludeItems `json:"includes"` 77 Include Include `json:"-"` 78 } 79 80 // CreateIncludeRequest contains parameters used to create an include 81 CreateIncludeRequest struct { 82 ContractID string `json:"-"` 83 GroupID string `json:"-"` 84 IncludeName string `json:"includeName"` 85 IncludeType IncludeType `json:"includeType"` 86 ProductID string `json:"productId"` 87 RuleFormat string `json:"ruleFormat,omitempty"` 88 CloneIncludeFrom *CloneIncludeFrom `json:"cloneFrom,omitempty"` 89 } 90 91 // CreateIncludeResponse represents a response object returned by CreateInclude 92 CreateIncludeResponse struct { 93 IncludeID string `json:"-"` 94 IncludeLink string `json:"includeLink"` 95 ResponseHeaders CreateIncludeResponseHeaders 96 } 97 98 // DeleteIncludeRequest contains parameters used to delete an include 99 DeleteIncludeRequest struct { 100 ContractID string 101 GroupID string 102 IncludeID string 103 } 104 105 // DeleteIncludeResponse represents a response object returned by DeleteInclude 106 DeleteIncludeResponse struct { 107 Message string `json:"message"` 108 } 109 110 // CloneIncludeFrom optionally identifies another include instance to clone when making a request to create new include 111 CloneIncludeFrom struct { 112 CloneFromVersionEtag string `json:"cloneFromVersionEtag,omitempty"` 113 IncludeID string `json:"includeId"` 114 Version int `json:"version"` 115 } 116 117 // CreateIncludeResponseHeaders contains information received in response headers when making a request to create new include 118 CreateIncludeResponseHeaders struct { 119 IncludesLimitTotal string 120 IncludesLimitRemaining string 121 } 122 123 // Include represents an Include object 124 Include struct { 125 AccountID string `json:"accountId"` 126 AssetID string `json:"assetId"` 127 ContractID string `json:"contractId"` 128 GroupID string `json:"groupId"` 129 IncludeID string `json:"includeId"` 130 IncludeName string `json:"includeName"` 131 IncludeType IncludeType `json:"includeType"` 132 LatestVersion int `json:"latestVersion"` 133 ProductionVersion *int `json:"productionVersion"` 134 PropertyType *string `json:"propertyType"` 135 StagingVersion *int `json:"stagingVersion"` 136 } 137 138 // IncludeItems represents a list of Include objects 139 IncludeItems struct { 140 Items []Include `json:"items"` 141 } 142 143 // ParentProperty represents an include parent object 144 ParentProperty struct { 145 AccountID string `json:"accountId"` 146 AssetID string `json:"assetId"` 147 ContractID string `json:"contractId"` 148 GroupID string `json:"groupId"` 149 ProductionVersion *int `json:"productionVersion,omitempty"` 150 PropertyID string `json:"propertyId"` 151 PropertyName string `json:"propertyName"` 152 StagingVersion *int `json:"stagingVersion,omitempty"` 153 } 154 155 // ParentPropertyItems represents a list of ParentProperty objects 156 ParentPropertyItems struct { 157 Items []ParentProperty `json:"items"` 158 } 159 160 // IncludeType is type of include 161 IncludeType string 162 ) 163 164 const ( 165 // IncludeTypeMicroServices is used for creating a new microservices include 166 IncludeTypeMicroServices IncludeType = "MICROSERVICES" 167 168 // IncludeTypeCommonSettings is used for creating a new common_settings include 169 IncludeTypeCommonSettings IncludeType = "COMMON_SETTINGS" 170 ) 171 172 // Validate validates ListIncludesRequest 173 func (i ListIncludesRequest) Validate() error { 174 return validation.Errors{ 175 "ContractID": validation.Validate(i.ContractID, validation.Required), 176 }.Filter() 177 } 178 179 // Validate validates ListIncludeParentsRequest 180 func (i ListIncludeParentsRequest) Validate() error { 181 return validation.Errors{ 182 "IncludeID": validation.Validate(i.IncludeID, validation.Required), 183 }.Filter() 184 } 185 186 // Validate validates GetIncludeRequest 187 func (i GetIncludeRequest) Validate() error { 188 errs := validation.Errors{ 189 "ContractID": validation.Validate(i.ContractID, validation.Required), 190 "GroupID": validation.Validate(i.GroupID, validation.Required), 191 "IncludeID": validation.Validate(i.IncludeID, validation.Required), 192 } 193 194 return edgegriderr.ParseValidationErrors(errs) 195 } 196 197 // Validate validates CreateIncludeRequest 198 func (i CreateIncludeRequest) Validate() error { 199 errs := validation.Errors{ 200 "ContractID": validation.Validate(i.ContractID, validation.Required), 201 "GroupID": validation.Validate(i.GroupID, validation.Required), 202 "IncludeName": validation.Validate(i.IncludeName, validation.Required), 203 "IncludeType": validation.Validate(i.IncludeType, validation.Required, validation.In(IncludeTypeMicroServices, IncludeTypeCommonSettings)), 204 "ProductID": validation.Validate(i.ProductID, validation.Required), 205 "CloneIncludeFrom.IncludeID": validation.Validate(i.CloneIncludeFrom, validation.When(i.CloneIncludeFrom != nil, validation.By(validateCloneIncludeID))), 206 "CloneIncludeFrom.Version": validation.Validate(i.CloneIncludeFrom, validation.When(i.CloneIncludeFrom != nil, validation.By(validateCloneVersion))), 207 } 208 209 return edgegriderr.ParseValidationErrors(errs) 210 } 211 212 // Validate validates DeleteIncludeRequest 213 func (i DeleteIncludeRequest) Validate() error { 214 return validation.Errors{ 215 "IncludeID": validation.Validate(i.IncludeID, validation.Required), 216 }.Filter() 217 } 218 219 // validateCloneIncludeID validates IncludeID under CloneIncludeFrom 220 func validateCloneIncludeID(value interface{}) error { 221 v, ok := value.(*CloneIncludeFrom) 222 if !ok { 223 return fmt.Errorf("type %T is invalid. Must be *CloneIncludeFrom", value) 224 } 225 226 if v.IncludeID == "" { 227 return fmt.Errorf("cannot be blank") 228 } 229 230 return nil 231 } 232 233 // validateCloneVersion validates Version under CloneIncludeFrom 234 func validateCloneVersion(value interface{}) error { 235 v, ok := value.(*CloneIncludeFrom) 236 if !ok { 237 return fmt.Errorf("type %T is invalid. Must be *CloneIncludeFrom", value) 238 } 239 240 if v.Version == 0 { 241 return fmt.Errorf("cannot be blank") 242 } 243 244 return nil 245 } 246 247 var ( 248 // ErrListIncludes is returned in case an error occurs on ListIncludes operation 249 ErrListIncludes = errors.New("list Includes") 250 // ErrListIncludeParents is returned in case an error occurs on ListIncludeParents operation 251 ErrListIncludeParents = errors.New("list Include Parents") 252 // ErrGetInclude is returned in case an error occurs on GetInclude operation 253 ErrGetInclude = errors.New("get an Include") 254 // ErrCreateInclude is returned in case an error occurs on CreateInclude operation 255 ErrCreateInclude = errors.New("create an Include") 256 // ErrDeleteInclude is returned in case an error occurs on DeleteInclude operation 257 ErrDeleteInclude = errors.New("delete an Include") 258 ) 259 260 func (p *papi) ListIncludes(ctx context.Context, params ListIncludesRequest) (*ListIncludesResponse, error) { 261 logger := p.Log(ctx) 262 logger.Debug("ListIncludes") 263 264 if err := params.Validate(); err != nil { 265 return nil, fmt.Errorf("%s: %w: %s", ErrListIncludes, ErrStructValidation, err) 266 } 267 268 uri, err := url.Parse("/papi/v1/includes") 269 if err != nil { 270 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListIncludes, err) 271 } 272 273 q := uri.Query() 274 q.Add("contractId", params.ContractID) 275 if params.GroupID != "" { 276 q.Add("groupId", params.GroupID) 277 } 278 uri.RawQuery = q.Encode() 279 280 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 281 if err != nil { 282 return nil, fmt.Errorf("%w: failed to create request: %s", ErrListIncludes, err) 283 } 284 285 var result ListIncludesResponse 286 resp, err := p.Exec(req, &result) 287 if err != nil { 288 return nil, fmt.Errorf("%s: request failed: %w", ErrListIncludes, err) 289 } 290 291 if resp.StatusCode != http.StatusOK { 292 return nil, fmt.Errorf("%s: %w", ErrListIncludes, p.Error(resp)) 293 } 294 295 return &result, nil 296 } 297 298 func (p *papi) ListIncludeParents(ctx context.Context, params ListIncludeParentsRequest) (*ListIncludeParentsResponse, error) { 299 logger := p.Log(ctx) 300 logger.Debug("ListIncludeParents") 301 302 if err := params.Validate(); err != nil { 303 return nil, fmt.Errorf("%s: %w: %s", ErrListIncludeParents, ErrStructValidation, err) 304 } 305 306 uri, err := url.Parse(fmt.Sprintf("/papi/v1/includes/%s/parents", params.IncludeID)) 307 if err != nil { 308 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListIncludeParents, err) 309 } 310 311 q := uri.Query() 312 if params.ContractID != "" { 313 q.Add("contractId", params.ContractID) 314 } 315 if params.GroupID != "" { 316 q.Add("groupId", params.GroupID) 317 } 318 uri.RawQuery = q.Encode() 319 320 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 321 if err != nil { 322 return nil, fmt.Errorf("%w: failed to create request: %s", ErrListIncludeParents, err) 323 } 324 325 var result ListIncludeParentsResponse 326 resp, err := p.Exec(req, &result) 327 if err != nil { 328 return nil, fmt.Errorf("%w: request failed: %s", ErrListIncludeParents, err) 329 } 330 331 if resp.StatusCode != http.StatusOK { 332 return nil, fmt.Errorf("%s: %w", ErrListIncludeParents, p.Error(resp)) 333 } 334 335 return &result, nil 336 } 337 338 func (p *papi) GetInclude(ctx context.Context, params GetIncludeRequest) (*GetIncludeResponse, error) { 339 logger := p.Log(ctx) 340 logger.Debug("GetInclude") 341 342 if err := params.Validate(); err != nil { 343 return nil, fmt.Errorf("%s: %w: %s", ErrGetInclude, ErrStructValidation, err) 344 } 345 346 uri, err := url.Parse(fmt.Sprintf("/papi/v1/includes/%s", params.IncludeID)) 347 if err != nil { 348 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetInclude, err) 349 } 350 351 q := uri.Query() 352 q.Add("contractId", params.ContractID) 353 q.Add("groupId", params.GroupID) 354 uri.RawQuery = q.Encode() 355 356 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 357 if err != nil { 358 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetInclude, err) 359 } 360 361 var result GetIncludeResponse 362 resp, err := p.Exec(req, &result) 363 if err != nil { 364 return nil, fmt.Errorf("%w: request failed: %s", ErrGetInclude, err) 365 } 366 367 if resp.StatusCode != http.StatusOK { 368 return nil, fmt.Errorf("%s: %w", ErrGetInclude, p.Error(resp)) 369 } 370 371 if len(result.Includes.Items) == 0 { 372 return nil, fmt.Errorf("%s: %w: IncludeID: %s", ErrGetInclude, ErrNotFound, params.IncludeID) 373 } 374 result.Include = result.Includes.Items[0] 375 376 return &result, nil 377 } 378 379 func (p *papi) CreateInclude(ctx context.Context, params CreateIncludeRequest) (*CreateIncludeResponse, error) { 380 logger := p.Log(ctx) 381 logger.Debug("CreateInclude") 382 383 if err := params.Validate(); err != nil { 384 return nil, fmt.Errorf("%s: %w: %s", ErrCreateInclude, ErrStructValidation, err) 385 } 386 387 uri, err := url.Parse("/papi/v1/includes") 388 if err != nil { 389 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrCreateInclude, err) 390 } 391 392 q := uri.Query() 393 q.Add("contractId", params.ContractID) 394 q.Add("groupId", params.GroupID) 395 uri.RawQuery = q.Encode() 396 397 req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) 398 if err != nil { 399 return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateInclude, err) 400 } 401 402 var result CreateIncludeResponse 403 resp, err := p.Exec(req, &result, params) 404 if err != nil { 405 return nil, fmt.Errorf("%w: request failed: %s", ErrCreateInclude, err) 406 } 407 408 if resp.StatusCode != http.StatusCreated { 409 return nil, fmt.Errorf("%s: %w", ErrCreateInclude, p.Error(resp)) 410 } 411 412 result.ResponseHeaders.IncludesLimitTotal = resp.Header.Get("x-limit-includes-per-contract-limit") 413 result.ResponseHeaders.IncludesLimitRemaining = resp.Header.Get("x-limit-includes-per-contract-remaining") 414 415 id, err := ResponseLinkParse(result.IncludeLink) 416 if err != nil { 417 return nil, fmt.Errorf("%s: %w: %s", ErrCreateInclude, ErrInvalidResponseLink, err) 418 } 419 result.IncludeID = id 420 421 return &result, nil 422 } 423 424 func (p *papi) DeleteInclude(ctx context.Context, params DeleteIncludeRequest) (*DeleteIncludeResponse, error) { 425 logger := p.Log(ctx) 426 logger.Debug("DeleteInclude") 427 428 if err := params.Validate(); err != nil { 429 return nil, fmt.Errorf("%s: %w: %s", ErrDeleteInclude, ErrStructValidation, err) 430 } 431 432 uri, err := url.Parse(fmt.Sprintf("/papi/v1/includes/%s", params.IncludeID)) 433 if err != nil { 434 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrDeleteInclude, err) 435 } 436 437 q := uri.Query() 438 if params.ContractID != "" { 439 q.Add("contractId", params.ContractID) 440 } 441 if params.GroupID != "" { 442 q.Add("groupId", params.GroupID) 443 } 444 uri.RawQuery = q.Encode() 445 446 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri.String(), nil) 447 if err != nil { 448 return nil, fmt.Errorf("%w: failed to create request: %s", ErrDeleteInclude, err) 449 } 450 451 var result DeleteIncludeResponse 452 resp, err := p.Exec(req, &result) 453 if err != nil { 454 return nil, fmt.Errorf("%w: request failed: %s", ErrDeleteInclude, err) 455 } 456 457 if resp.StatusCode != http.StatusOK { 458 return nil, fmt.Errorf("%s: %w", ErrDeleteInclude, p.Error(resp)) 459 } 460 461 return &result, nil 462 }