Skip to content

Commit d48b0b1

Browse files
api-clients-generation-pipeline[bot]ci.datadog-api-spec
andauthored
Add new DeleteAssignee endpoint to Error Tracking APIs (#968)
Co-authored-by: ci.datadog-api-spec <packages@datadoghq.com>
1 parent 34f87e9 commit d48b0b1

10 files changed

+297
-0
lines changed

.generator/schemas/v2/openapi.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61011,6 +61011,35 @@ paths:
6101161011
tags:
6101261012
- Error Tracking
6101361013
/api/v2/error-tracking/issues/{issue_id}/assignee:
61014+
delete:
61015+
description: Remove the assignee of an issue by `issue_id`.
61016+
operationId: DeleteIssueAssignee
61017+
parameters:
61018+
- $ref: '#/components/parameters/IssueIDPathParameter'
61019+
responses:
61020+
'204':
61021+
description: No Content
61022+
'400':
61023+
$ref: '#/components/responses/BadRequestResponse'
61024+
'401':
61025+
$ref: '#/components/responses/UnauthorizedResponse'
61026+
'403':
61027+
$ref: '#/components/responses/ForbiddenResponse'
61028+
'404':
61029+
$ref: '#/components/responses/NotFoundResponse'
61030+
'429':
61031+
$ref: '#/components/responses/TooManyRequestsResponse'
61032+
security:
61033+
- apiKeyAuth: []
61034+
appKeyAuth: []
61035+
- AuthZ:
61036+
- error_tracking_read
61037+
- error_tracking_write
61038+
- cases_read
61039+
- cases_write
61040+
summary: Remove the assignee of an issue
61041+
tags:
61042+
- Error Tracking
6101461043
put:
6101561044
description: Update the assignee of an issue by `issue_id`.
6101661045
operationId: UpdateIssueAssignee
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Remove the assignee of an issue returns "No Content" response
2+
use datadog_api_client::datadog;
3+
use datadog_api_client::datadogV2::api_error_tracking::ErrorTrackingAPI;
4+
5+
#[tokio::main]
6+
async fn main() {
7+
// there is a valid "issue" in the system
8+
let issue_id = std::env::var("ISSUE_ID").unwrap();
9+
let configuration = datadog::Configuration::new();
10+
let api = ErrorTrackingAPI::with_config(configuration);
11+
let resp = api.delete_issue_assignee(issue_id.clone()).await;
12+
if let Ok(value) = resp {
13+
println!("{:#?}", value);
14+
} else {
15+
println!("{:#?}", resp.unwrap_err());
16+
}
17+
}

src/datadogV2/api/api_error_tracking.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ impl SearchIssuesOptionalParams {
4848
}
4949
}
5050

51+
/// DeleteIssueAssigneeError is a struct for typed errors of method [`ErrorTrackingAPI::delete_issue_assignee`]
52+
#[derive(Debug, Clone, Serialize, Deserialize)]
53+
#[serde(untagged)]
54+
pub enum DeleteIssueAssigneeError {
55+
APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
56+
UnknownValue(serde_json::Value),
57+
}
58+
5159
/// GetIssueError is a struct for typed errors of method [`ErrorTrackingAPI::get_issue`]
5260
#[derive(Debug, Clone, Serialize, Deserialize)]
5361
#[serde(untagged)]
@@ -145,6 +153,94 @@ impl ErrorTrackingAPI {
145153
Self { config, client }
146154
}
147155

156+
/// Remove the assignee of an issue by `issue_id`.
157+
pub async fn delete_issue_assignee(
158+
&self,
159+
issue_id: String,
160+
) -> Result<(), datadog::Error<DeleteIssueAssigneeError>> {
161+
match self.delete_issue_assignee_with_http_info(issue_id).await {
162+
Ok(_) => Ok(()),
163+
Err(err) => Err(err),
164+
}
165+
}
166+
167+
/// Remove the assignee of an issue by `issue_id`.
168+
pub async fn delete_issue_assignee_with_http_info(
169+
&self,
170+
issue_id: String,
171+
) -> Result<datadog::ResponseContent<()>, datadog::Error<DeleteIssueAssigneeError>> {
172+
let local_configuration = &self.config;
173+
let operation_id = "v2.delete_issue_assignee";
174+
175+
let local_client = &self.client;
176+
177+
let local_uri_str = format!(
178+
"{}/api/v2/error-tracking/issues/{issue_id}/assignee",
179+
local_configuration.get_operation_host(operation_id),
180+
issue_id = datadog::urlencode(issue_id)
181+
);
182+
let mut local_req_builder =
183+
local_client.request(reqwest::Method::DELETE, local_uri_str.as_str());
184+
185+
// build headers
186+
let mut headers = HeaderMap::new();
187+
headers.insert("Accept", HeaderValue::from_static("*/*"));
188+
189+
// build user agent
190+
match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
191+
Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
192+
Err(e) => {
193+
log::warn!("Failed to parse user agent header: {e}, falling back to default");
194+
headers.insert(
195+
reqwest::header::USER_AGENT,
196+
HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
197+
)
198+
}
199+
};
200+
201+
// build auth
202+
if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
203+
headers.insert(
204+
"DD-API-KEY",
205+
HeaderValue::from_str(local_key.key.as_str())
206+
.expect("failed to parse DD-API-KEY header"),
207+
);
208+
};
209+
if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
210+
headers.insert(
211+
"DD-APPLICATION-KEY",
212+
HeaderValue::from_str(local_key.key.as_str())
213+
.expect("failed to parse DD-APPLICATION-KEY header"),
214+
);
215+
};
216+
217+
local_req_builder = local_req_builder.headers(headers);
218+
let local_req = local_req_builder.build()?;
219+
log::debug!("request content: {:?}", local_req.body());
220+
let local_resp = local_client.execute(local_req).await?;
221+
222+
let local_status = local_resp.status();
223+
let local_content = local_resp.text().await?;
224+
log::debug!("response content: {}", local_content);
225+
226+
if !local_status.is_client_error() && !local_status.is_server_error() {
227+
Ok(datadog::ResponseContent {
228+
status: local_status,
229+
content: local_content,
230+
entity: None,
231+
})
232+
} else {
233+
let local_entity: Option<DeleteIssueAssigneeError> =
234+
serde_json::from_str(&local_content).ok();
235+
let local_error = datadog::ResponseContent {
236+
status: local_status,
237+
content: local_content,
238+
entity: local_entity,
239+
};
240+
Err(datadog::Error::ResponseError(local_error))
241+
}
242+
}
243+
148244
/// Retrieve the full details for a specific error tracking issue, including attributes and relationships.
149245
pub async fn get_issue(
150246
&self,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2025-10-17T14:43:40.022Z
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"http_interactions": [
3+
{
4+
"request": {
5+
"body": {
6+
"string": "{\"data\":{\"attributes\":{\"from\":1759416220000,\"query\":\"service:synthetics-browser\",\"to\":1760712220000,\"track\":\"rum\"},\"type\":\"search_request\"}}",
7+
"encoding": null
8+
},
9+
"headers": {
10+
"Accept": [
11+
"application/json"
12+
],
13+
"Content-Type": [
14+
"application/json"
15+
]
16+
},
17+
"method": "post",
18+
"uri": "https://api.datadoghq.com/api/v2/error-tracking/issues/search"
19+
},
20+
"response": {
21+
"body": {
22+
"string": "{\"data\":[{\"id\":\"d3ab59c6-84ee-11f0-87bb-da7ad0900002\",\"type\":\"error_tracking_search_result\",\"attributes\":{\"impacted_sessions\":4316,\"total_count\":8640},\"relationships\":{\"issue\":{\"data\":{\"id\":\"d3ab59c6-84ee-11f0-87bb-da7ad0900002\",\"type\":\"issue\"}}}},{\"id\":\"a5bb2896-a4d0-11f0-bd76-da7ad0900002\",\"type\":\"error_tracking_search_result\",\"attributes\":{\"impacted_sessions\":280,\"total_count\":272},\"relationships\":{\"issue\":{\"data\":{\"id\":\"a5bb2896-a4d0-11f0-bd76-da7ad0900002\",\"type\":\"issue\"}}}},{\"id\":\"e2a89d14-6f07-11f0-8a88-da7ad0900002\",\"type\":\"error_tracking_search_result\",\"attributes\":{\"impacted_sessions\":1,\"total_count\":4},\"relationships\":{\"issue\":{\"data\":{\"id\":\"e2a89d14-6f07-11f0-8a88-da7ad0900002\",\"type\":\"issue\"}}}},{\"id\":\"5f8ebd5c-6dd9-11f0-8a28-da7ad0900002\",\"type\":\"error_tracking_search_result\",\"attributes\":{\"impacted_sessions\":1,\"total_count\":1},\"relationships\":{\"issue\":{\"data\":{\"id\":\"5f8ebd5c-6dd9-11f0-8a28-da7ad0900002\",\"type\":\"issue\"}}}},{\"id\":\"e2a89134-6f07-11f0-8d36-da7ad0900002\",\"type\":\"error_tracking_search_result\",\"attributes\":{\"impacted_sessions\":1,\"total_count\":1},\"relationships\":{\"issue\":{\"data\":{\"id\":\"e2a89134-6f07-11f0-8d36-da7ad0900002\",\"type\":\"issue\"}}}}]}",
23+
"encoding": null
24+
},
25+
"headers": {
26+
"Content-Type": [
27+
"application/vnd.api+json"
28+
]
29+
},
30+
"status": {
31+
"code": 200,
32+
"message": "OK"
33+
}
34+
},
35+
"recorded_at": "Fri, 17 Oct 2025 14:43:40 GMT"
36+
},
37+
{
38+
"request": {
39+
"body": "",
40+
"headers": {
41+
"Accept": [
42+
"*/*"
43+
]
44+
},
45+
"method": "delete",
46+
"uri": "https://api.datadoghq.com/api/v2/error-tracking/issues/d3ab59c6-84ee-11f0-87bb-da7ad0900002/assignee"
47+
},
48+
"response": {
49+
"body": {
50+
"string": "",
51+
"encoding": null
52+
},
53+
"headers": {},
54+
"status": {
55+
"code": 204,
56+
"message": "No Content"
57+
}
58+
},
59+
"recorded_at": "Fri, 17 Oct 2025 14:43:40 GMT"
60+
}
61+
],
62+
"recorded_with": "VCR 6.0.0"
63+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2025-10-17T14:43:41.755Z
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"http_interactions": [
3+
{
4+
"request": {
5+
"body": "",
6+
"headers": {
7+
"Accept": [
8+
"*/*"
9+
]
10+
},
11+
"method": "delete",
12+
"uri": "https://api.datadoghq.com/api/v2/error-tracking/issues/67d80aa3-36ff-44b9-a694-c501a7591737/assignee"
13+
},
14+
"response": {
15+
"body": {
16+
"string": "{\"errors\":[{\"status\":\"404\",\"title\":\"Not Found\",\"detail\":\"issue not found\"}]}",
17+
"encoding": null
18+
},
19+
"headers": {
20+
"Content-Type": [
21+
"application/vnd.api+json"
22+
]
23+
},
24+
"status": {
25+
"code": 404,
26+
"message": "Not Found"
27+
}
28+
},
29+
"recorded_at": "Fri, 17 Oct 2025 14:43:41 GMT"
30+
}
31+
],
32+
"recorded_with": "VCR 6.0.0"
33+
}

tests/scenarios/features/v2/error_tracking.feature

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,28 @@ Feature: Error Tracking
3232
Then the response status is 200 OK
3333
And the response "data.id" is equal to "{{ issue.id }}"
3434

35+
@generated @skip @team:DataDog/error-tracking
36+
Scenario: Remove the assignee of an issue returns "Bad Request" response
37+
Given new "DeleteIssueAssignee" request
38+
And request contains "issue_id" parameter from "REPLACE.ME"
39+
When the request is sent
40+
Then the response status is 400 Bad Request
41+
42+
@team:DataDog/error-tracking
43+
Scenario: Remove the assignee of an issue returns "No Content" response
44+
Given new "DeleteIssueAssignee" request
45+
And there is a valid "issue" in the system
46+
And request contains "issue_id" parameter from "issue.id"
47+
When the request is sent
48+
Then the response status is 204 No Content
49+
50+
@team:DataDog/error-tracking
51+
Scenario: Remove the assignee of an issue returns "Not Found" response
52+
Given new "DeleteIssueAssignee" request
53+
And request contains "issue_id" parameter with value "67d80aa3-36ff-44b9-a694-c501a7591737"
54+
When the request is sent
55+
Then the response status is 404 Not Found
56+
3557
@team:DataDog/error-tracking
3658
Scenario: Search error tracking issues returns "Bad Request" response
3759
Given new "SearchIssues" request

tests/scenarios/features/v2/undo.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,12 @@
13191319
"type": "safe"
13201320
}
13211321
},
1322+
"DeleteIssueAssignee": {
1323+
"tag": "Error Tracking",
1324+
"undo": {
1325+
"type": "idempotent"
1326+
}
1327+
},
13221328
"UpdateIssueAssignee": {
13231329
"tag": "Error Tracking",
13241330
"undo": {

tests/scenarios/function_mappings.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2838,6 +2838,10 @@ pub fn collect_function_calls(world: &mut DatadogWorld) {
28382838
world
28392839
.function_mappings
28402840
.insert("v2.GetIssue".into(), test_v2_get_issue);
2841+
world.function_mappings.insert(
2842+
"v2.DeleteIssueAssignee".into(),
2843+
test_v2_delete_issue_assignee,
2844+
);
28412845
world.function_mappings.insert(
28422846
"v2.UpdateIssueAssignee".into(),
28432847
test_v2_update_issue_assignee,
@@ -21008,6 +21012,31 @@ fn test_v2_get_issue(world: &mut DatadogWorld, _parameters: &HashMap<String, Val
2100821012
world.response.code = response.status.as_u16();
2100921013
}
2101021014

21015+
fn test_v2_delete_issue_assignee(world: &mut DatadogWorld, _parameters: &HashMap<String, Value>) {
21016+
let api = world
21017+
.api_instances
21018+
.v2_api_error_tracking
21019+
.as_ref()
21020+
.expect("api instance not found");
21021+
let issue_id = serde_json::from_value(_parameters.get("issue_id").unwrap().clone()).unwrap();
21022+
let response = match block_on(api.delete_issue_assignee_with_http_info(issue_id)) {
21023+
Ok(response) => response,
21024+
Err(error) => {
21025+
return match error {
21026+
Error::ResponseError(e) => {
21027+
world.response.code = e.status.as_u16();
21028+
if let Some(entity) = e.entity {
21029+
world.response.object = serde_json::to_value(entity).unwrap();
21030+
}
21031+
}
21032+
_ => panic!("error parsing response: {error}"),
21033+
};
21034+
}
21035+
};
21036+
world.response.object = serde_json::to_value(response.entity).unwrap();
21037+
world.response.code = response.status.as_u16();
21038+
}
21039+
2101121040
fn test_v2_update_issue_assignee(world: &mut DatadogWorld, _parameters: &HashMap<String, Value>) {
2101221041
let api = world
2101321042
.api_instances

0 commit comments

Comments
 (0)