github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/papi/propertyversion.go (about) 1 package papi 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "net/http" 9 "net/url" 10 "strconv" 11 12 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" 13 validation "github.com/go-ozzo/ozzo-validation/v4" 14 ) 15 16 type ( 17 // PropertyVersions contains operations available on PropertyVersions resource 18 PropertyVersions interface { 19 // GetPropertyVersions fetches available property versions 20 // 21 // See: https://techdocs.akamai.com/property-mgr/reference/get-property-versions 22 GetPropertyVersions(context.Context, GetPropertyVersionsRequest) (*GetPropertyVersionsResponse, error) 23 24 // GetPropertyVersion fetches specific property version 25 // 26 // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version 27 GetPropertyVersion(context.Context, GetPropertyVersionRequest) (*GetPropertyVersionsResponse, error) 28 29 // CreatePropertyVersion creates a new property version and returns location and number for the new version 30 // 31 // See: https://techdocs.akamai.com/property-mgr/reference/post-property-versions 32 CreatePropertyVersion(context.Context, CreatePropertyVersionRequest) (*CreatePropertyVersionResponse, error) 33 34 // GetLatestVersion fetches the latest property version 35 // 36 // See: https://techdocs.akamai.com/property-mgr/reference/get-latest-property-version 37 GetLatestVersion(context.Context, GetLatestVersionRequest) (*GetPropertyVersionsResponse, error) 38 39 // GetAvailableBehaviors fetches a list of available behaviors for given property version 40 // 41 // See: https://techdocs.akamai.com/property-mgr/reference/get-available-behaviors 42 GetAvailableBehaviors(context.Context, GetAvailableBehaviorsRequest) (*GetBehaviorsResponse, error) 43 44 // GetAvailableCriteria fetches a list of available criteria for given property version 45 // 46 // See: https://techdocs.akamai.com/property-mgr/reference/get-available-criteria 47 GetAvailableCriteria(context.Context, GetAvailableCriteriaRequest) (*GetCriteriaResponse, error) 48 49 // ListAvailableIncludes lists external resources that can be applied within a property version's rules 50 // 51 // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-external-resources 52 ListAvailableIncludes(context.Context, ListAvailableIncludesRequest) (*ListAvailableIncludesResponse, error) 53 54 // ListReferencedIncludes lists referenced includes for parent property 55 // 56 // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-includes 57 ListReferencedIncludes(context.Context, ListReferencedIncludesRequest) (*ListReferencedIncludesResponse, error) 58 } 59 60 // GetPropertyVersionsRequest contains path and query params used for listing property versions 61 GetPropertyVersionsRequest struct { 62 PropertyID string 63 ContractID string 64 GroupID string 65 Limit int 66 Offset int 67 } 68 69 // GetPropertyVersionsResponse contains GET response returned while fetching property versions or specific version 70 GetPropertyVersionsResponse struct { 71 PropertyID string `json:"propertyId"` 72 PropertyName string `json:"propertyName"` 73 AccountID string `json:"accountId"` 74 ContractID string `json:"contractId"` 75 GroupID string `json:"groupId"` 76 AssetID string `json:"assetId"` 77 Versions PropertyVersionItems `json:"versions"` 78 Version PropertyVersionGetItem 79 } 80 81 // PropertyVersionItems contains collection of property version details 82 PropertyVersionItems struct { 83 Items []PropertyVersionGetItem `json:"items"` 84 } 85 86 // PropertyVersionGetItem contains detailed information about specific property version returned in GET 87 PropertyVersionGetItem struct { 88 Etag string `json:"etag"` 89 Note string `json:"note"` 90 ProductID string `json:"productId"` 91 ProductionStatus VersionStatus `json:"productionStatus"` 92 PropertyVersion int `json:"propertyVersion"` 93 RuleFormat string `json:"ruleFormat"` 94 StagingStatus VersionStatus `json:"stagingStatus"` 95 UpdatedByUser string `json:"updatedByUser"` 96 UpdatedDate string `json:"updatedDate"` 97 } 98 99 // GetPropertyVersionRequest contains path and query params used for fetching specific property version 100 GetPropertyVersionRequest struct { 101 PropertyID string 102 PropertyVersion int 103 ContractID string 104 GroupID string 105 } 106 107 // CreatePropertyVersionRequest contains path and query params, as well as request body required to execute POST /versions request 108 CreatePropertyVersionRequest struct { 109 PropertyID string 110 ContractID string 111 GroupID string 112 Version PropertyVersionCreate 113 } 114 115 // PropertyVersionCreate contains request body used in POST /versions request 116 PropertyVersionCreate struct { 117 CreateFromVersion int `json:"createFromVersion"` 118 CreateFromVersionEtag string `json:"createFromVersionEtag,omitempty"` 119 } 120 121 // CreatePropertyVersionResponse contains a link returned after creating new property version and version number of this version 122 CreatePropertyVersionResponse struct { 123 VersionLink string `json:"versionLink"` 124 PropertyVersion int 125 } 126 127 // GetLatestVersionRequest contains path and query params required to fetch latest property version 128 GetLatestVersionRequest struct { 129 PropertyID string 130 ActivatedOn string 131 ContractID string 132 GroupID string 133 } 134 135 // GetAvailableItemsRequest contains path and query params required to fetch available behaviors or criteria for a property 136 GetAvailableItemsRequest struct { 137 PropertyID string 138 PropertyVersion int 139 ContractID string 140 GroupID string 141 } 142 143 // GetAvailableBehaviorsRequest contains path and query params required to fetch available behaviors for a property 144 GetAvailableBehaviorsRequest GetAvailableItemsRequest 145 146 // GetAvailableCriteriaRequest contains path and query params required to fetch available criteria for a property 147 GetAvailableCriteriaRequest GetAvailableItemsRequest 148 149 // GetBehaviorsResponse represents a response object returned by GetAvailableBehaviors 150 GetBehaviorsResponse AvailableBehaviorsResponse 151 152 // GetCriteriaResponse represents a response object returned by GetAvailableCriteria 153 GetCriteriaResponse AvailableCriteriaResponse 154 155 // VersionStatus represents ProductionVersion and StagingVersion of a Version struct 156 VersionStatus string 157 158 // ListAvailableIncludesRequest contains path and query params required to fetch list of available includes 159 ListAvailableIncludesRequest ListAvailableReferencedIncludesRequest 160 161 // ListReferencedIncludesRequest contains path and query params required to fetch list of referenced includes 162 ListReferencedIncludesRequest ListAvailableReferencedIncludesRequest 163 164 //ListAvailableReferencedIncludesRequest common request struct for ListReferencedIncludesRequest and ListAvailableIncludesRequest 165 ListAvailableReferencedIncludesRequest struct { 166 PropertyID string 167 PropertyVersion int 168 ContractID string 169 GroupID string 170 } 171 172 // ListAvailableIncludesResponse contains response received when fetching list of available includes 173 ListAvailableIncludesResponse struct { 174 AvailableIncludes []ExternalIncludeData 175 } 176 177 // ListReferencedIncludesResponse contains response received when fetching list of referenced includes 178 // The response from the API is a map, but we convert it to the array for better usability. 179 ListReferencedIncludesResponse struct { 180 Includes IncludeItems `json:"includes"` 181 } 182 183 // ExternalIncludeData contains data for a specific include from AvailableIncludes 184 ExternalIncludeData struct { 185 IncludeID string `json:"id"` 186 IncludeName string `json:"name"` 187 IncludeType IncludeType `json:"includeType"` 188 FileName string `json:"fileName"` 189 ProductName string `json:"productName"` 190 RuleFormat string `json:"ruleFormat"` 191 } 192 ) 193 194 const ( 195 // VersionStatusActive const 196 VersionStatusActive VersionStatus = "ACTIVE" 197 // VersionStatusInactive const 198 VersionStatusInactive VersionStatus = "INACTIVE" 199 // VersionStatusPending const 200 VersionStatusPending VersionStatus = "PENDING" 201 // VersionStatusDeactivated const 202 VersionStatusDeactivated VersionStatus = "DEACTIVATED" 203 // VersionProduction const 204 VersionProduction = "PRODUCTION" 205 // VersionStaging const 206 VersionStaging = "STAGING" 207 ) 208 209 // Validate validates GetPropertyVersionsRequest 210 func (v GetPropertyVersionsRequest) Validate() error { 211 return validation.Errors{ 212 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 213 }.Filter() 214 } 215 216 // Validate validates GetPropertyVersionRequest 217 func (v GetPropertyVersionRequest) Validate() error { 218 return validation.Errors{ 219 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 220 "PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required), 221 }.Filter() 222 } 223 224 // Validate validates CreatePropertyVersionRequest 225 func (v CreatePropertyVersionRequest) Validate() error { 226 errs := validation.Errors{ 227 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 228 "Version": validation.Validate(v.Version), 229 } 230 return edgegriderr.ParseValidationErrors(errs) 231 } 232 233 // Validate validates PropertyVersionCreate 234 func (v PropertyVersionCreate) Validate() error { 235 return validation.Errors{ 236 "CreateFromVersion": validation.Validate(v.CreateFromVersion, validation.Required), 237 }.Filter() 238 } 239 240 // Validate validates GetLatestVersionRequest 241 func (v GetLatestVersionRequest) Validate() error { 242 return validation.Errors{ 243 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 244 "ActivatedOn": validation.Validate(v.ActivatedOn, validation.In(VersionProduction, VersionStaging)), 245 }.Filter() 246 } 247 248 // Validate validates GetAvailableBehaviorsRequest 249 func (v GetAvailableBehaviorsRequest) Validate() error { 250 return validation.Errors{ 251 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 252 "PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required), 253 }.Filter() 254 } 255 256 // Validate validates GetAvailableCriteriaRequest 257 func (v GetAvailableCriteriaRequest) Validate() error { 258 return validation.Errors{ 259 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 260 "PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required), 261 }.Filter() 262 } 263 264 // Validate validates ListAvailableIncludesRequest 265 func (v ListAvailableIncludesRequest) Validate() error { 266 return validation.Errors{ 267 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 268 "PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required), 269 }.Filter() 270 } 271 272 // Validate validates ListReferencedIncludesRequest 273 func (v ListReferencedIncludesRequest) Validate() error { 274 return validation.Errors{ 275 "PropertyID": validation.Validate(v.PropertyID, validation.Required), 276 "PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required), 277 "GroupID": validation.Validate(v.GroupID, validation.Required), 278 "ContractID": validation.Validate(v.ContractID, validation.Required), 279 }.Filter() 280 } 281 282 var ( 283 // ErrGetPropertyVersions represents error when fetching property versions fails 284 ErrGetPropertyVersions = errors.New("fetching property versions") 285 // ErrGetPropertyVersion represents error when fetching property version fails 286 ErrGetPropertyVersion = errors.New("fetching property version") 287 // ErrGetLatestVersion represents error when fetching latest property version fails 288 ErrGetLatestVersion = errors.New("fetching latest property version") 289 // ErrCreatePropertyVersion represents error when creating property version fails 290 ErrCreatePropertyVersion = errors.New("creating property version") 291 // ErrGetAvailableBehaviors represents error when fetching available behaviors fails 292 ErrGetAvailableBehaviors = errors.New("fetching available behaviors") 293 // ErrGetAvailableCriteria represents error when fetching available criteria fails 294 ErrGetAvailableCriteria = errors.New("fetching available criteria") 295 // ErrListAvailableIncludes represents error when fetching available includes 296 ErrListAvailableIncludes = errors.New("fetching available includes") 297 // ErrListReferencedIncludes represents error when fetching referenced includes 298 ErrListReferencedIncludes = errors.New("fetching referenced includes") 299 ) 300 301 func (p *papi) GetPropertyVersions(ctx context.Context, params GetPropertyVersionsRequest) (*GetPropertyVersionsResponse, error) { 302 if err := params.Validate(); err != nil { 303 return nil, fmt.Errorf("%s: %w: %s", ErrGetPropertyVersions, ErrStructValidation, err) 304 } 305 306 logger := p.Log(ctx) 307 logger.Debug("GetPropertyVersions") 308 309 getURL := fmt.Sprintf( 310 "/papi/v1/properties/%s/versions?contractId=%s&groupId=%s", 311 params.PropertyID, 312 params.ContractID, 313 params.GroupID, 314 ) 315 if params.Limit != 0 { 316 getURL += fmt.Sprintf("&limit=%d", params.Limit) 317 } 318 if params.Offset != 0 { 319 getURL += fmt.Sprintf("&offset=%d", params.Offset) 320 } 321 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 322 if err != nil { 323 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPropertyVersions, err) 324 } 325 326 var versions GetPropertyVersionsResponse 327 resp, err := p.Exec(req, &versions) 328 if err != nil { 329 return nil, fmt.Errorf("%w: request failed: %s", ErrGetPropertyVersions, err) 330 } 331 332 if resp.StatusCode != http.StatusOK { 333 return nil, fmt.Errorf("%s: %w", ErrGetPropertyVersions, p.Error(resp)) 334 } 335 336 return &versions, nil 337 } 338 339 func (p *papi) GetLatestVersion(ctx context.Context, params GetLatestVersionRequest) (*GetPropertyVersionsResponse, error) { 340 if err := params.Validate(); err != nil { 341 return nil, fmt.Errorf("%s: %w: %s", ErrGetLatestVersion, ErrStructValidation, err) 342 } 343 344 logger := p.Log(ctx) 345 logger.Debug("GetLatestVersion") 346 347 getURL := fmt.Sprintf( 348 "/papi/v1/properties/%s/versions/latest?contractId=%s&groupId=%s", 349 params.PropertyID, 350 params.ContractID, 351 params.GroupID, 352 ) 353 if params.ActivatedOn != "" { 354 getURL += fmt.Sprintf("&activatedOn=%s", params.ActivatedOn) 355 } 356 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 357 if err != nil { 358 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetLatestVersion, err) 359 } 360 361 var version GetPropertyVersionsResponse 362 resp, err := p.Exec(req, &version) 363 if err != nil { 364 return nil, fmt.Errorf("%w: request failed: %s", ErrGetLatestVersion, err) 365 } 366 367 if resp.StatusCode != http.StatusOK { 368 return nil, fmt.Errorf("%s: %w", ErrGetLatestVersion, p.Error(resp)) 369 } 370 if len(version.Versions.Items) == 0 { 371 return nil, fmt.Errorf("%s: %w: latest version for PropertyID: %s", ErrGetLatestVersion, ErrNotFound, params.PropertyID) 372 } 373 version.Version = version.Versions.Items[0] 374 return &version, nil 375 } 376 377 func (p *papi) GetPropertyVersion(ctx context.Context, params GetPropertyVersionRequest) (*GetPropertyVersionsResponse, error) { 378 if err := params.Validate(); err != nil { 379 return nil, fmt.Errorf("%s: %w: %s", ErrGetPropertyVersion, ErrStructValidation, err) 380 } 381 382 logger := p.Log(ctx) 383 logger.Debug("GetPropertyVersion") 384 385 getURL := fmt.Sprintf( 386 "/papi/v1/properties/%s/versions/%d?contractId=%s&groupId=%s", 387 params.PropertyID, 388 params.PropertyVersion, 389 params.ContractID, 390 params.GroupID, 391 ) 392 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 393 if err != nil { 394 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPropertyVersion, err) 395 } 396 397 var versions GetPropertyVersionsResponse 398 resp, err := p.Exec(req, &versions) 399 if err != nil { 400 return nil, fmt.Errorf("%w: request failed: %s", ErrGetPropertyVersion, err) 401 } 402 403 if resp.StatusCode != http.StatusOK { 404 return nil, fmt.Errorf("%s: %w", ErrGetPropertyVersion, p.Error(resp)) 405 } 406 if len(versions.Versions.Items) == 0 { 407 return nil, fmt.Errorf("%s: %w: Version %d for PropertyID: %s", ErrGetPropertyVersion, ErrNotFound, params.PropertyVersion, params.PropertyID) 408 } 409 versions.Version = versions.Versions.Items[0] 410 return &versions, nil 411 } 412 413 func (p *papi) CreatePropertyVersion(ctx context.Context, request CreatePropertyVersionRequest) (*CreatePropertyVersionResponse, error) { 414 if err := request.Validate(); err != nil { 415 return nil, fmt.Errorf("%s: %w:\n%s", ErrCreatePropertyVersion, ErrStructValidation, err) 416 } 417 418 logger := p.Log(ctx) 419 logger.Debug("CreatePropertyVersion") 420 421 getURL := fmt.Sprintf( 422 "/papi/v1/properties/%s/versions?contractId=%s&groupId=%s", 423 request.PropertyID, 424 request.ContractID, 425 request.GroupID, 426 ) 427 req, err := http.NewRequestWithContext(ctx, http.MethodPost, getURL, nil) 428 if err != nil { 429 return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreatePropertyVersion, err) 430 } 431 432 var version CreatePropertyVersionResponse 433 resp, err := p.Exec(req, &version, request.Version) 434 if err != nil { 435 return nil, fmt.Errorf("%w: request failed: %s", ErrCreatePropertyVersion, err) 436 } 437 438 if resp.StatusCode != http.StatusCreated { 439 return nil, fmt.Errorf("%s: %w", ErrCreatePropertyVersion, p.Error(resp)) 440 } 441 propertyVersion, err := ResponseLinkParse(version.VersionLink) 442 if err != nil { 443 return nil, fmt.Errorf("%s: %w: %s", ErrCreatePropertyVersion, ErrInvalidResponseLink, err) 444 } 445 versionNumber, err := strconv.Atoi(propertyVersion) 446 if err != nil { 447 return nil, fmt.Errorf("%s: %w: %s: %s", ErrCreatePropertyVersion, ErrInvalidResponseLink, "version should be a number", propertyVersion) 448 } 449 version.PropertyVersion = versionNumber 450 return &version, nil 451 } 452 453 func (p *papi) GetAvailableBehaviors(ctx context.Context, params GetAvailableBehaviorsRequest) (*GetBehaviorsResponse, error) { 454 if err := params.Validate(); err != nil { 455 return nil, fmt.Errorf("%s: %w: %s", ErrGetAvailableBehaviors, ErrStructValidation, err) 456 } 457 458 logger := p.Log(ctx) 459 logger.Debug("GetAvailableBehaviors") 460 461 uri, err := url.Parse(fmt.Sprintf("/papi/v1/properties/%s/versions/%d/available-behaviors", params.PropertyID, params.PropertyVersion)) 462 if err != nil { 463 return nil, fmt.Errorf("%w: failed to parse uri: %s", ErrGetAvailableBehaviors, err) 464 } 465 466 q := uri.Query() 467 if params.ContractID != "" { 468 q.Add("contractId", params.ContractID) 469 } 470 if params.GroupID != "" { 471 q.Add("groupId", params.GroupID) 472 } 473 uri.RawQuery = q.Encode() 474 475 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 476 if err != nil { 477 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetAvailableBehaviors, err) 478 } 479 480 var behaviors GetBehaviorsResponse 481 resp, err := p.Exec(req, &behaviors) 482 if err != nil { 483 return nil, fmt.Errorf("%w: request failed: %s", ErrGetAvailableBehaviors, err) 484 } 485 486 if resp.StatusCode != http.StatusOK { 487 return nil, fmt.Errorf("%s: %w", ErrGetAvailableBehaviors, p.Error(resp)) 488 } 489 490 return &behaviors, nil 491 } 492 493 func (p *papi) GetAvailableCriteria(ctx context.Context, params GetAvailableCriteriaRequest) (*GetCriteriaResponse, error) { 494 if err := params.Validate(); err != nil { 495 return nil, fmt.Errorf("%s: %w: %s", ErrGetAvailableCriteria, ErrStructValidation, err) 496 } 497 498 logger := p.Log(ctx) 499 logger.Debug("GetAvailableCriteria") 500 501 uri, err := url.Parse(fmt.Sprintf("/papi/v1/properties/%s/versions/%d/available-criteria", params.PropertyID, params.PropertyVersion)) 502 if err != nil { 503 return nil, fmt.Errorf("%w: failed to parse uri: %s", ErrGetAvailableCriteria, err) 504 } 505 506 q := uri.Query() 507 if params.ContractID != "" { 508 q.Add("contractId", params.ContractID) 509 } 510 if params.GroupID != "" { 511 q.Add("groupId", params.GroupID) 512 } 513 uri.RawQuery = q.Encode() 514 515 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 516 if err != nil { 517 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetAvailableCriteria, err) 518 } 519 520 var criteria GetCriteriaResponse 521 resp, err := p.Exec(req, &criteria) 522 if err != nil { 523 return nil, fmt.Errorf("%w: request failed: %s", ErrGetAvailableCriteria, err) 524 } 525 526 if resp.StatusCode != http.StatusOK { 527 return nil, fmt.Errorf("%s: %w", ErrGetAvailableCriteria, p.Error(resp)) 528 } 529 530 return &criteria, nil 531 } 532 533 func (p *papi) ListAvailableIncludes(ctx context.Context, params ListAvailableIncludesRequest) (*ListAvailableIncludesResponse, error) { 534 logger := p.Log(ctx) 535 logger.Debug("ListAvailableIncludes") 536 537 if err := params.Validate(); err != nil { 538 return nil, fmt.Errorf("%s: %w: %s", ErrListAvailableIncludes, ErrStructValidation, err) 539 } 540 541 uri, err := url.Parse(fmt.Sprintf("/papi/v1/properties/%s/versions/%d/external-resources", params.PropertyID, params.PropertyVersion)) 542 if err != nil { 543 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListAvailableIncludes, err) 544 } 545 546 q := uri.Query() 547 if params.ContractID != "" { 548 q.Add("contractId", params.ContractID) 549 } 550 if params.GroupID != "" { 551 q.Add("groupId", params.GroupID) 552 } 553 uri.RawQuery = q.Encode() 554 555 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 556 if err != nil { 557 return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAvailableIncludes, err) 558 } 559 560 var result ListAvailableIncludesResponse 561 resp, err := p.Exec(req, &result) 562 if err != nil { 563 return nil, fmt.Errorf("%w: request failed: %s", ErrListAvailableIncludes, err) 564 } 565 566 if resp.StatusCode != http.StatusOK { 567 return nil, fmt.Errorf("%s: %w", ErrListAvailableIncludes, p.Error(resp)) 568 } 569 570 return &result, nil 571 } 572 573 func (p *papi) ListReferencedIncludes(ctx context.Context, params ListReferencedIncludesRequest) (*ListReferencedIncludesResponse, error) { 574 logger := p.Log(ctx) 575 logger.Debug("ListReferencedIncludes") 576 577 if err := params.Validate(); err != nil { 578 return nil, fmt.Errorf("%s: %w: %s", ErrListReferencedIncludes, ErrStructValidation, err) 579 } 580 581 uri, err := url.Parse(fmt.Sprintf("/papi/v1/properties/%s/versions/%d/includes", params.PropertyID, params.PropertyVersion)) 582 if err != nil { 583 return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListReferencedIncludes, err) 584 } 585 586 q := uri.Query() 587 if params.ContractID != "" { 588 q.Add("contractId", params.ContractID) 589 } 590 if params.GroupID != "" { 591 q.Add("groupId", params.GroupID) 592 } 593 uri.RawQuery = q.Encode() 594 595 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) 596 if err != nil { 597 return nil, fmt.Errorf("%w: failed to create request: %s", ErrListReferencedIncludes, err) 598 } 599 600 var result ListReferencedIncludesResponse 601 resp, err := p.Exec(req, &result) 602 if err != nil { 603 return nil, fmt.Errorf("%w: request failed: %s", ErrListReferencedIncludes, err) 604 } 605 606 if resp.StatusCode != http.StatusOK { 607 return nil, fmt.Errorf("%s: %w", ErrListReferencedIncludes, p.Error(resp)) 608 } 609 610 return &result, nil 611 } 612 613 // UnmarshalJSON reads a ListAvailableIncludesResponse struct from its data argument and transform map of includes into array for better usability. 614 func (r *ListAvailableIncludesResponse) UnmarshalJSON(data []byte) error { 615 var response struct { 616 ExternalResources struct { 617 ExternalIncludes map[string]ExternalIncludeData `json:"include"` 618 } `json:"externalResources"` 619 } 620 621 if err := json.Unmarshal(data, &response); err != nil { 622 return err 623 } 624 625 r.AvailableIncludes = make([]ExternalIncludeData, 0, len(response.ExternalResources.ExternalIncludes)) 626 for _, include := range response.ExternalResources.ExternalIncludes { 627 r.AvailableIncludes = append(r.AvailableIncludes, include) 628 } 629 630 return nil 631 }