Skip to content

Adds async Scorecard outcomes batch update endpoint #2646

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .generated-info
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"spec_repo_commit": "8001cbb",
"generated": "2025-08-13 20:28:25.331"
"spec_repo_commit": "c9f30db",
"generated": "2025-08-15 16:36:42.349"
}
86 changes: 86 additions & 0 deletions .generator/schemas/v2/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14454,6 +14454,10 @@ components:
description: Entity definition in raw JSON or YAML representation.
example: "apiVersion: v3\nkind: service\nmetadata:\n name: myservice\n"
type: string
EntityReference:
description: The unique reference for an IDP entity.
example: service:my-service
type: string
EntityRelationships:
description: Entity relationships.
properties:
Expand Down Expand Up @@ -43591,6 +43595,57 @@ components:
id:
$ref: '#/components/schemas/ApiID'
type: object
UpdateOutcomesAsyncAttributes:
description: The JSON:API attributes for a batched set of scorecard outcomes.
properties:
results:
description: Set of scorecard outcomes to update asynchronously.
items:
$ref: '#/components/schemas/UpdateOutcomesAsyncRequestItem'
type: array
type: object
UpdateOutcomesAsyncRequest:
description: Scorecard outcomes batch request.
properties:
data:
$ref: '#/components/schemas/UpdateOutcomesAsyncRequestData'
type: object
UpdateOutcomesAsyncRequestData:
description: Scorecard outcomes batch request data.
properties:
attributes:
$ref: '#/components/schemas/UpdateOutcomesAsyncAttributes'
type:
$ref: '#/components/schemas/UpdateOutcomesAsyncType'
type: object
UpdateOutcomesAsyncRequestItem:
description: Scorecard outcome for a single entity and rule.
properties:
entity_reference:
$ref: '#/components/schemas/EntityReference'
remarks:
description: Any remarks regarding the scorecard rule's evaluation, and
supports HTML hyperlinks.
example: 'See: <a href="https://app.datadoghq.com/services">Services</a>'
type: string
rule_id:
$ref: '#/components/schemas/RuleId'
state:
$ref: '#/components/schemas/State'
required:
- rule_id
- entity_reference
- state
type: object
UpdateOutcomesAsyncType:
default: batched-outcome
description: The JSON:API type for scorecard outcomes.
enum:
- batched-outcome
example: batched-outcome
type: string
x-enum-varnames:
- BATCHED_OUTCOME
UpdateResourceEvaluationFiltersRequest:
description: Request object to update a resource filter.
properties:
Expand Down Expand Up @@ -61575,6 +61630,37 @@ paths:
resultsPath: data
x-unstable: '**Note**: This endpoint is in public beta.

If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).'
post:
description: Updates multiple scorecard rule outcomes in a single batched request.
operationId: UpdateScorecardOutcomesAsync
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateOutcomesAsyncRequest'
description: Set of scorecard outcomes.
required: true
responses:
'202':
description: Accepted
'400':
$ref: '#/components/responses/BadRequestResponse'
'403':
$ref: '#/components/responses/ForbiddenResponse'
'429':
$ref: '#/components/responses/TooManyRequestsResponse'
security:
- apiKeyAuth: []
appKeyAuth: []
- AuthZ:
- apm_service_catalog_write
summary: Update Scorecard outcomes asynchronously
tags:
- Service Scorecards
x-codegen-request-body-name: body
x-unstable: '**Note**: This endpoint is in public beta.

If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).'
/api/v2/scorecard/outcomes/batch:
post:
Expand Down
36 changes: 36 additions & 0 deletions examples/v2/service-scorecards/UpdateScorecardOutcomesAsync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Update Scorecard outcomes asynchronously returns "Accepted" response
*/

import { client, v2 } from "@datadog/datadog-api-client";

const configuration = client.createConfiguration();
configuration.unstableOperations["v2.updateScorecardOutcomesAsync"] = true;
const apiInstance = new v2.ServiceScorecardsApi(configuration);

const params: v2.ServiceScorecardsApiUpdateScorecardOutcomesAsyncRequest = {
body: {
data: {
attributes: {
results: [
{
entityReference: "service:my-service",
remarks: `See: <a href="https://app.datadoghq.com/services">Services</a>`,
ruleId: "q8MQxk8TCqrHnWkx",
state: "pass",
},
],
},
type: "batched-outcome",
},
},
};

apiInstance
.updateScorecardOutcomesAsync(params)
.then((data: any) => {
console.log(
"API called successfully. Returned data: " + JSON.stringify(data)
);
})
.catch((error: any) => console.error(error));
7 changes: 7 additions & 0 deletions features/support/scenarios_model_mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7102,6 +7102,13 @@ export const ScenariosModelMappings: {[key: string]: {[key: string]: any}} = {
},
"operationResponseType": "OutcomesResponse",
},
"v2.UpdateScorecardOutcomesAsync": {
"body": {
"type": "UpdateOutcomesAsyncRequest",
"format": "",
},
"operationResponseType": "void",
},
"v2.CreateScorecardOutcomesBatch": {
"body": {
"type": "OutcomesBatchRequest",
Expand Down
16 changes: 16 additions & 0 deletions features/v2/service_scorecards.feature
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,22 @@ Feature: Service Scorecards
Then the response status is 200 OK
And the response has 4 items

@generated @skip @team:DataDog/service-catalog
Scenario: Update Scorecard outcomes asynchronously returns "Accepted" response
Given operation "UpdateScorecardOutcomesAsync" enabled
And new "UpdateScorecardOutcomesAsync" request
And body with value {"data": {"attributes": {"results": [{"entity_reference": "service:my-service", "remarks": "See: <a href=\"https://app.datadoghq.com/services\">Services</a>", "rule_id": "q8MQxk8TCqrHnWkx", "state": "pass"}]}, "type": "batched-outcome"}}
When the request is sent
Then the response status is 202 Accepted

@generated @skip @team:DataDog/service-catalog
Scenario: Update Scorecard outcomes asynchronously returns "Bad Request" response
Given operation "UpdateScorecardOutcomesAsync" enabled
And new "UpdateScorecardOutcomesAsync" request
And body with value {"data": {"attributes": {"results": [{"entity_reference": "service:my-service", "remarks": "See: <a href=\"https://app.datadoghq.com/services\">Services</a>", "rule_id": "q8MQxk8TCqrHnWkx", "state": "pass"}]}, "type": "batched-outcome"}}
When the request is sent
Then the response status is 400 Bad Request

@generated @skip @team:DataDog/service-catalog
Scenario: Update an existing rule returns "Bad Request" response
Given operation "UpdateScorecardRule" enabled
Expand Down
6 changes: 6 additions & 0 deletions features/v2/undo.json
Original file line number Diff line number Diff line change
Expand Up @@ -2742,6 +2742,12 @@
"type": "safe"
}
},
"UpdateScorecardOutcomesAsync": {
"tag": "Service Scorecards",
"undo": {
"type": "idempotent"
}
},
"CreateScorecardOutcomesBatch": {
"tag": "Service Scorecards",
"undo": {
Expand Down
1 change: 1 addition & 0 deletions packages/datadog-api-client-common/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ export function createConfiguration(
"v2.deleteScorecardRule": false,
"v2.listScorecardOutcomes": false,
"v2.listScorecardRules": false,
"v2.updateScorecardOutcomesAsync": false,
"v2.updateScorecardRule": false,
"v2.createIncidentService": false,
"v2.deleteIncidentService": false,
Expand Down
137 changes: 137 additions & 0 deletions packages/datadog-api-client-v2/apis/ServiceScorecardsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { OutcomesBatchRequest } from "../models/OutcomesBatchRequest";
import { OutcomesBatchResponse } from "../models/OutcomesBatchResponse";
import { OutcomesResponse } from "../models/OutcomesResponse";
import { OutcomesResponseDataItem } from "../models/OutcomesResponseDataItem";
import { UpdateOutcomesAsyncRequest } from "../models/UpdateOutcomesAsyncRequest";
import { UpdateRuleRequest } from "../models/UpdateRuleRequest";
import { UpdateRuleResponse } from "../models/UpdateRuleResponse";

Expand Down Expand Up @@ -388,6 +389,55 @@ export class ServiceScorecardsApiRequestFactory extends BaseAPIRequestFactory {
return requestContext;
}

public async updateScorecardOutcomesAsync(
body: UpdateOutcomesAsyncRequest,
_options?: Configuration
): Promise<RequestContext> {
const _config = _options || this.configuration;

logger.warn("Using unstable operation 'updateScorecardOutcomesAsync'");
if (!_config.unstableOperations["v2.updateScorecardOutcomesAsync"]) {
throw new Error(
"Unstable operation 'updateScorecardOutcomesAsync' is disabled"
);
}

// verify required parameter 'body' is not null or undefined
if (body === null || body === undefined) {
throw new RequiredError("body", "updateScorecardOutcomesAsync");
}

// Path Params
const localVarPath = "/api/v2/scorecard/outcomes";

// Make Request Context
const requestContext = _config
.getServer("v2.ServiceScorecardsApi.updateScorecardOutcomesAsync")
.makeRequestContext(localVarPath, HttpMethod.POST);
requestContext.setHeaderParam("Accept", "*/*");
requestContext.setHttpConfig(_config.httpConfig);

// Body Params
const contentType = ObjectSerializer.getPreferredMediaType([
"application/json",
]);
requestContext.setHeaderParam("Content-Type", contentType);
const serializedBody = ObjectSerializer.stringify(
ObjectSerializer.serialize(body, "UpdateOutcomesAsyncRequest", ""),
contentType
);
requestContext.setBody(serializedBody);

// Apply auth methods
applySecurityAuthentication(_config, requestContext, [
"apiKeyAuth",
"appKeyAuth",
"AuthZ",
]);

return requestContext;
}

public async updateScorecardRule(
ruleId: string,
body: UpdateRuleRequest,
Expand Down Expand Up @@ -751,6 +801,64 @@ export class ServiceScorecardsApiResponseProcessor {
);
}

/**
* Unwraps the actual response sent by the server from the response context and deserializes the response content
* to the expected objects
*
* @params response Response returned by the server for a request to updateScorecardOutcomesAsync
* @throws ApiException if the response code was not in [200, 299]
*/
public async updateScorecardOutcomesAsync(
response: ResponseContext
): Promise<void> {
const contentType = ObjectSerializer.normalizeMediaType(
response.headers["content-type"]
);
if (response.httpStatusCode === 202) {
return;
}
if (
response.httpStatusCode === 400 ||
response.httpStatusCode === 403 ||
response.httpStatusCode === 429
) {
const bodyText = ObjectSerializer.parse(
await response.body.text(),
contentType
);
let body: APIErrorResponse;
try {
body = ObjectSerializer.deserialize(
bodyText,
"APIErrorResponse"
) as APIErrorResponse;
} catch (error) {
logger.debug(`Got error deserializing error: ${error}`);
throw new ApiException<APIErrorResponse>(
response.httpStatusCode,
bodyText
);
}
throw new ApiException<APIErrorResponse>(response.httpStatusCode, body);
}

// Work around for missing responses in specification, e.g. for petstore.yaml
if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) {
const body: void = ObjectSerializer.deserialize(
ObjectSerializer.parse(await response.body.text(), contentType),
"void",
""
) as void;
return body;
}

const body = (await response.body.text()) || "";
throw new ApiException<string>(
response.httpStatusCode,
'Unknown API Status Code!\nBody: "' + body + '"'
);
}

/**
* Unwraps the actual response sent by the server from the response context and deserializes the response content
* to the expected objects
Expand Down Expand Up @@ -944,6 +1052,14 @@ export interface ServiceScorecardsApiListScorecardRulesRequest {
fieldsScorecard?: string;
}

export interface ServiceScorecardsApiUpdateScorecardOutcomesAsyncRequest {
/**
* Set of scorecard outcomes.
* @type UpdateOutcomesAsyncRequest
*/
body: UpdateOutcomesAsyncRequest;
}

export interface ServiceScorecardsApiUpdateScorecardRuleRequest {
/**
* The ID of the rule.
Expand Down Expand Up @@ -1201,6 +1317,27 @@ export class ServiceScorecardsApi {
}
}

/**
* Updates multiple scorecard rule outcomes in a single batched request.
* @param param The request object
*/
public updateScorecardOutcomesAsync(
param: ServiceScorecardsApiUpdateScorecardOutcomesAsyncRequest,
options?: Configuration
): Promise<void> {
const requestContextPromise =
this.requestFactory.updateScorecardOutcomesAsync(param.body, options);
return requestContextPromise.then((requestContext) => {
return this.configuration.httpApi
.send(requestContext)
.then((responseContext) => {
return this.responseProcessor.updateScorecardOutcomesAsync(
responseContext
);
});
});
}

/**
* Updates an existing rule.
* @param param The request object
Expand Down
Loading