diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index abac03b8a..1d7a005fe 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -41237,6 +41237,114 @@ components: type: string x-enum-varnames: - PROCESS + ProductAnalyticsServerSideEventError: + description: Error details. + properties: + detail: + description: Error message. + example: Malformed payload + type: string + status: + description: Error code. + example: '400' + type: string + title: + description: Error title. + example: Bad Request + type: string + type: object + ProductAnalyticsServerSideEventErrors: + description: Error response. + properties: + errors: + description: Structured errors. + items: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventError' + type: array + type: object + ProductAnalyticsServerSideEventItem: + description: A Product Analytics server-side event. + properties: + account: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItemAccount' + application: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItemApplication' + event: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItemEvent' + session: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItemSession' + type: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItemType' + usr: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItemUsr' + required: + - application + - event + - type + type: object + ProductAnalyticsServerSideEventItemAccount: + description: The account linked to your event. + properties: + id: + description: The account ID used in Datadog. + example: account-67890 + type: string + required: + - id + type: object + ProductAnalyticsServerSideEventItemApplication: + description: The application in which you want to send your events. + properties: + id: + description: 'The application ID of your application. It can be found in + your + + [application management page](https://app.datadoghq.com/rum/list).' + example: 123abcde-123a-123b-1234-123456789abc + type: string + required: + - id + type: object + ProductAnalyticsServerSideEventItemEvent: + description: Fields used for the event. + properties: + name: + description: The name of your event, which is used for search in the same + way as view or action names. + example: payment.processed + type: string + required: + - name + type: object + ProductAnalyticsServerSideEventItemSession: + description: The session linked to your event. + properties: + id: + description: The session ID captured by the SDK. + example: session-abcdef + type: string + required: + - id + type: object + ProductAnalyticsServerSideEventItemType: + description: The type of Product Analytics event. Must be `server` for server-side + events. + enum: + - server + example: server + type: string + x-enum-varnames: + - SERVER + ProductAnalyticsServerSideEventItemUsr: + description: The user linked to your event. + properties: + id: + description: The user ID used in Datadog. + example: user-12345 + type: string + required: + - id + type: object Project: description: A Project properties: @@ -78009,6 +78117,218 @@ paths: x-permission: operator: OPEN permissions: [] + /api/v2/prodlytics: + post: + description: 'Send server-side events to Product Analytics. Server-side events + are retained for 15 months. + + + Server-Side events in Product Analytics are helpful for tracking events that + occur on the server, + + as opposed to client-side events, which are captured by Real User Monitoring + (RUM) SDKs. + + This allows for a more comprehensive view of the user journey by including + actions that happen on the server. + + Typical examples could be `checkout.completed` or `payment.processed`. + + + Ingested server-side events are integrated into Product Analytics to allow + users to select and filter + + these events in the event picker, similar to how views or actions are handled. + + + **Requirements:** + + - At least one of `usr`, `account`, or `session` must be provided with a valid + ID. + + - The `application.id` must reference a Product Analytics-enabled application. + + + **Custom Attributes:** + + Any additional fields in the payload are flattened and searchable as facets. + + For example, a payload with `{"customer": {"tier": "premium"}}` is searchable + with + + the syntax `@customer.tier:premium` in Datadog. + + + The status codes answered by the HTTP API are: + + - 202: Accepted: The request has been accepted for processing + + - 400: Bad request (likely an issue in the payload formatting) + + - 401: Unauthorized (likely a missing API Key) + + - 403: Permission issue (likely using an invalid API Key) + + - 408: Request Timeout, request should be retried after some time + + - 413: Payload too large (batch is above 5MB uncompressed) + + - 429: Too Many Requests, request should be retried after some time + + - 500: Internal Server Error, the server encountered an unexpected condition + that prevented it from fulfilling the request, request should be retried after + some time + + - 503: Service Unavailable, the server is not ready to handle the request + probably because it is overloaded, request should be retried after some time' + operationId: SubmitProductAnalyticsEvent + requestBody: + content: + application/json: + examples: + event-with-account: + description: Send a server-side event linked to an account. + summary: Event with account ID + value: + account: + id: account-456 + application: + id: 123abcde-123a-123b-1234-123456789abc + event: + name: checkout.completed + type: server + event-with-custom-attributes: + description: Send a server-side event with additional custom attributes. + summary: Event with custom attributes + value: + application: + id: 123abcde-123a-123b-1234-123456789abc + customer: + tier: premium + event: + name: payment.processed + type: server + usr: + id: '123' + event-with-session: + description: Send a server-side event linked to a session. + summary: Event with session ID + value: + application: + id: 123abcde-123a-123b-1234-123456789abc + event: + name: form.submitted + session: + id: session-789 + type: server + simple-event-with-user: + description: Send a server-side event linked to a user. + summary: Simple event with user ID + value: + application: + id: 123abcde-123a-123b-1234-123456789abc + event: + name: payment.processed + type: server + usr: + id: '123' + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventItem' + description: Server-side event to send (JSON format). + required: true + responses: + '202': + content: + application/json: + schema: + type: object + description: Request accepted for processing (always 202 empty JSON). + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Bad Request + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Unauthorized + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Forbidden + '408': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Request Timeout + '413': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Payload Too Large + '429': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Too Many Requests + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Internal Server Error + '503': + content: + application/json: + schema: + $ref: '#/components/schemas/ProductAnalyticsServerSideEventErrors' + description: Service Unavailable + security: + - apiKeyAuth: [] + servers: + - url: https://{subdomain}.{site} + variables: + site: + default: datadoghq.com + description: The regional site for customers. + enum: + - datadoghq.com + - us3.datadoghq.com + - us5.datadoghq.com + - ap1.datadoghq.com + - ap2.datadoghq.com + - datadoghq.eu + subdomain: + default: browser-intake + description: The subdomain where the API is deployed. + - url: '{protocol}://{name}' + variables: + name: + default: browser-intake-datadoghq.com + description: Full site DNS name. + protocol: + default: https + description: The protocol for accessing the API. + - url: https://{subdomain}.{site} + variables: + site: + default: datadoghq.com + description: Any Datadog deployment. + subdomain: + default: browser-intake + description: The subdomain where the API is deployed. + summary: Send server-side events + tags: + - Product Analytics + x-codegen-request-body-name: body /api/v2/product-analytics/accounts/facet_info: post: description: Get facet information for account attributes including possible @@ -90205,6 +90525,18 @@ tags: See the [Live Processes page](https://docs.datadoghq.com/infrastructure/process/) for more information. name: Processes +- description: 'Send server-side events to Product Analytics. Server-Side Events Ingestion + allows you to collect custom events + + from any server-side source, and retains events for 15 months. Server-side events + are helpful for understanding + + causes of a funnel drop-off which are external to the client-side (for example, + payment processing error). + + See the [Product Analytics page](https://docs.datadoghq.com/product_analytics/) + for more information.' + name: Product Analytics - description: Manage your Real User Monitoring (RUM) applications, and search or aggregate your RUM events over HTTP. See the [RUM & Session Replay page](https://docs.datadoghq.com/real_user_monitoring/) for more information diff --git a/examples/v2_product-analytics_SubmitProductAnalyticsEvent.rs b/examples/v2_product-analytics_SubmitProductAnalyticsEvent.rs new file mode 100644 index 000000000..0727d7182 --- /dev/null +++ b/examples/v2_product-analytics_SubmitProductAnalyticsEvent.rs @@ -0,0 +1,39 @@ +// Send server-side events returns "Request accepted for processing (always 202 +// empty JSON)." response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_product_analytics::ProductAnalyticsAPI; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItem; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItemAccount; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItemApplication; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItemEvent; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItemSession; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItemType; +use datadog_api_client::datadogV2::model::ProductAnalyticsServerSideEventItemUsr; + +#[tokio::main] +async fn main() { + let body = ProductAnalyticsServerSideEventItem::new( + ProductAnalyticsServerSideEventItemApplication::new( + "123abcde-123a-123b-1234-123456789abc".to_string(), + ), + ProductAnalyticsServerSideEventItemEvent::new("payment.processed".to_string()), + ProductAnalyticsServerSideEventItemType::SERVER, + ) + .account(ProductAnalyticsServerSideEventItemAccount::new( + "account-67890".to_string(), + )) + .session(ProductAnalyticsServerSideEventItemSession::new( + "session-abcdef".to_string(), + )) + .usr(ProductAnalyticsServerSideEventItemUsr::new( + "user-12345".to_string(), + )); + let configuration = datadog::Configuration::new(); + let api = ProductAnalyticsAPI::with_config(configuration); + let resp = api.submit_product_analytics_event(body).await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/src/datadog/configuration.rs b/src/datadog/configuration.rs index 2eab236e9..170f5d430 100644 --- a/src/datadog/configuration.rs +++ b/src/datadog/configuration.rs @@ -988,6 +988,84 @@ lazy_static! { }, ], ), + ( + "v2.submit_product_analytics_event".into(), + vec![ + ServerConfiguration { + url: "https://{subdomain}.{site}".into(), + description: "No description provided".into(), + variables: HashMap::from([ + ( + "site".into(), + ServerVariable { + description: "The regional site for customers.".into(), + default_value: "datadoghq.com".into(), + enum_values: vec![ + "datadoghq.com".into(), + "us3.datadoghq.com".into(), + "us5.datadoghq.com".into(), + "ap1.datadoghq.com".into(), + "ap2.datadoghq.com".into(), + "datadoghq.eu".into(), + ], + }, + ), + ( + "subdomain".into(), + ServerVariable { + description: "The subdomain where the API is deployed.".into(), + default_value: "browser-intake".into(), + enum_values: vec![], + }, + ), + ]), + }, + ServerConfiguration { + url: "{protocol}://{name}".into(), + description: "No description provided".into(), + variables: HashMap::from([ + ( + "name".into(), + ServerVariable { + description: "Full site DNS name.".into(), + default_value: "browser-intake-datadoghq.com".into(), + enum_values: vec![], + }, + ), + ( + "protocol".into(), + ServerVariable { + description: "The protocol for accessing the API.".into(), + default_value: "https".into(), + enum_values: vec![], + }, + ), + ]), + }, + ServerConfiguration { + url: "https://{subdomain}.{site}".into(), + description: "No description provided".into(), + variables: HashMap::from([ + ( + "site".into(), + ServerVariable { + description: "Any Datadog deployment.".into(), + default_value: "datadoghq.com".into(), + enum_values: vec![], + }, + ), + ( + "subdomain".into(), + ServerVariable { + description: "The subdomain where the API is deployed.".into(), + default_value: "browser-intake".into(), + enum_values: vec![], + }, + ), + ]), + }, + ], + ), ]) }; } diff --git a/src/datadogV2/api/api_product_analytics.rs b/src/datadogV2/api/api_product_analytics.rs new file mode 100644 index 000000000..e125eb06b --- /dev/null +++ b/src/datadogV2/api/api_product_analytics.rs @@ -0,0 +1,296 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use crate::datadog; +use flate2::{ + write::{GzEncoder, ZlibEncoder}, + Compression, +}; +use reqwest::header::{HeaderMap, HeaderValue}; +use serde::{Deserialize, Serialize}; +use std::io::Write; + +/// SubmitProductAnalyticsEventError is a struct for typed errors of method [`ProductAnalyticsAPI::submit_product_analytics_event`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum SubmitProductAnalyticsEventError { + ProductAnalyticsServerSideEventErrors( + crate::datadogV2::model::ProductAnalyticsServerSideEventErrors, + ), + UnknownValue(serde_json::Value), +} + +/// Send server-side events to Product Analytics. Server-Side Events Ingestion allows you to collect custom events +/// from any server-side source, and retains events for 15 months. Server-side events are helpful for understanding +/// causes of a funnel drop-off which are external to the client-side (for example, payment processing error). +/// See the [Product Analytics page]() for more information. +#[derive(Debug, Clone)] +pub struct ProductAnalyticsAPI { + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, +} + +impl Default for ProductAnalyticsAPI { + fn default() -> Self { + Self::with_config(datadog::Configuration::default()) + } +} + +impl ProductAnalyticsAPI { + pub fn new() -> Self { + Self::default() + } + pub fn with_config(config: datadog::Configuration) -> Self { + let mut reqwest_client_builder = reqwest::Client::builder(); + + if let Some(proxy_url) = &config.proxy_url { + let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL"); + reqwest_client_builder = reqwest_client_builder.proxy(proxy); + } + + let mut middleware_client_builder = + reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap()); + + if config.enable_retry { + struct RetryableStatus; + impl reqwest_retry::RetryableStrategy for RetryableStatus { + fn handle( + &self, + res: &Result, + ) -> Option { + match res { + Ok(success) => reqwest_retry::default_on_request_success(success), + Err(_) => None, + } + } + } + let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder() + .build_with_max_retries(config.max_retries); + + let retry_middleware = + reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy( + backoff_policy, + RetryableStatus, + ); + + middleware_client_builder = middleware_client_builder.with(retry_middleware); + } + + let client = middleware_client_builder.build(); + + Self { config, client } + } + + pub fn with_client_and_config( + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, + ) -> Self { + Self { config, client } + } + + /// Send server-side events to Product Analytics. Server-side events are retained for 15 months. + /// + /// Server-Side events in Product Analytics are helpful for tracking events that occur on the server, + /// as opposed to client-side events, which are captured by Real User Monitoring (RUM) SDKs. + /// This allows for a more comprehensive view of the user journey by including actions that happen on the server. + /// Typical examples could be `checkout.completed` or `payment.processed`. + /// + /// Ingested server-side events are integrated into Product Analytics to allow users to select and filter + /// these events in the event picker, similar to how views or actions are handled. + /// + /// **Requirements:** + /// - At least one of `usr`, `account`, or `session` must be provided with a valid ID. + /// - The `application.id` must reference a Product Analytics-enabled application. + /// + /// **Custom Attributes:** + /// Any additional fields in the payload are flattened and searchable as facets. + /// For example, a payload with `{"customer": {"tier": "premium"}}` is searchable with + /// the syntax `@customer.tier:premium` in Datadog. + /// + /// The status codes answered by the HTTP API are: + /// - 202: Accepted: The request has been accepted for processing + /// - 400: Bad request (likely an issue in the payload formatting) + /// - 401: Unauthorized (likely a missing API Key) + /// - 403: Permission issue (likely using an invalid API Key) + /// - 408: Request Timeout, request should be retried after some time + /// - 413: Payload too large (batch is above 5MB uncompressed) + /// - 429: Too Many Requests, request should be retried after some time + /// - 500: Internal Server Error, the server encountered an unexpected condition that prevented it from fulfilling the request, request should be retried after some time + /// - 503: Service Unavailable, the server is not ready to handle the request probably because it is overloaded, request should be retried after some time + pub async fn submit_product_analytics_event( + &self, + body: crate::datadogV2::model::ProductAnalyticsServerSideEventItem, + ) -> Result< + std::collections::BTreeMap, + datadog::Error, + > { + match self + .submit_product_analytics_event_with_http_info(body) + .await + { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Send server-side events to Product Analytics. Server-side events are retained for 15 months. + /// + /// Server-Side events in Product Analytics are helpful for tracking events that occur on the server, + /// as opposed to client-side events, which are captured by Real User Monitoring (RUM) SDKs. + /// This allows for a more comprehensive view of the user journey by including actions that happen on the server. + /// Typical examples could be `checkout.completed` or `payment.processed`. + /// + /// Ingested server-side events are integrated into Product Analytics to allow users to select and filter + /// these events in the event picker, similar to how views or actions are handled. + /// + /// **Requirements:** + /// - At least one of `usr`, `account`, or `session` must be provided with a valid ID. + /// - The `application.id` must reference a Product Analytics-enabled application. + /// + /// **Custom Attributes:** + /// Any additional fields in the payload are flattened and searchable as facets. + /// For example, a payload with `{"customer": {"tier": "premium"}}` is searchable with + /// the syntax `@customer.tier:premium` in Datadog. + /// + /// The status codes answered by the HTTP API are: + /// - 202: Accepted: The request has been accepted for processing + /// - 400: Bad request (likely an issue in the payload formatting) + /// - 401: Unauthorized (likely a missing API Key) + /// - 403: Permission issue (likely using an invalid API Key) + /// - 408: Request Timeout, request should be retried after some time + /// - 413: Payload too large (batch is above 5MB uncompressed) + /// - 429: Too Many Requests, request should be retried after some time + /// - 500: Internal Server Error, the server encountered an unexpected condition that prevented it from fulfilling the request, request should be retried after some time + /// - 503: Service Unavailable, the server is not ready to handle the request probably because it is overloaded, request should be retried after some time + pub async fn submit_product_analytics_event_with_http_info( + &self, + body: crate::datadogV2::model::ProductAnalyticsServerSideEventItem, + ) -> Result< + datadog::ResponseContent>, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.submit_product_analytics_event"; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/prodlytics", + local_configuration.get_operation_host(operation_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::POST, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", HeaderValue::from_static("application/json")); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + + // build body parameters + let output = Vec::new(); + let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter); + if body.serialize(&mut ser).is_ok() { + if let Some(content_encoding) = headers.get("Content-Encoding") { + match content_encoding.to_str().unwrap_or_default() { + "gzip" => { + let mut enc = GzEncoder::new(Vec::new(), Compression::default()); + let _ = enc.write_all(ser.into_inner().as_slice()); + match enc.finish() { + Ok(buf) => { + local_req_builder = local_req_builder.body(buf); + } + Err(e) => return Err(datadog::Error::Io(e)), + } + } + "deflate" => { + let mut enc = ZlibEncoder::new(Vec::new(), Compression::default()); + let _ = enc.write_all(ser.into_inner().as_slice()); + match enc.finish() { + Ok(buf) => { + local_req_builder = local_req_builder.body(buf); + } + Err(e) => return Err(datadog::Error::Io(e)), + } + } + "zstd1" => { + let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap(); + let _ = enc.write_all(ser.into_inner().as_slice()); + match enc.finish() { + Ok(buf) => { + local_req_builder = local_req_builder.body(buf); + } + Err(e) => return Err(datadog::Error::Io(e)), + } + } + _ => { + local_req_builder = local_req_builder.body(ser.into_inner()); + } + } + } else { + local_req_builder = local_req_builder.body(ser.into_inner()); + } + } + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::>( + &local_content, + ) { + Ok(e) => { + return Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: Some(e), + }) + } + Err(e) => return Err(datadog::Error::Serde(e)), + }; + } else { + let local_entity: Option = + serde_json::from_str(&local_content).ok(); + let local_error = datadog::ResponseContent { + status: local_status, + content: local_content, + entity: local_entity, + }; + Err(datadog::Error::ResponseError(local_error)) + } + } +} diff --git a/src/datadogV2/api/mod.rs b/src/datadogV2/api/mod.rs index 4d3e9cb7e..1c89b3b0b 100644 --- a/src/datadogV2/api/mod.rs +++ b/src/datadogV2/api/mod.rs @@ -63,6 +63,7 @@ pub mod api_org_connections; pub mod api_organizations; pub mod api_powerpack; pub mod api_processes; +pub mod api_product_analytics; pub mod api_reference_tables; pub mod api_restriction_policies; pub mod api_roles; diff --git a/src/datadogV2/mod.rs b/src/datadogV2/mod.rs index 3d7767d4f..2ee0a112a 100644 --- a/src/datadogV2/mod.rs +++ b/src/datadogV2/mod.rs @@ -64,6 +64,7 @@ pub use self::api::api_org_connections; pub use self::api::api_organizations; pub use self::api::api_powerpack; pub use self::api::api_processes; +pub use self::api::api_product_analytics; pub use self::api::api_reference_tables; pub use self::api::api_restriction_policies; pub use self::api::api_roles; diff --git a/src/datadogV2/model/mod.rs b/src/datadogV2/model/mod.rs index 670570ff9..10d3adf90 100644 --- a/src/datadogV2/model/mod.rs +++ b/src/datadogV2/model/mod.rs @@ -4560,6 +4560,24 @@ pub mod model_process_summaries_meta; pub use self::model_process_summaries_meta::ProcessSummariesMeta; pub mod model_process_summaries_meta_page; pub use self::model_process_summaries_meta_page::ProcessSummariesMetaPage; +pub mod model_product_analytics_server_side_event_item; +pub use self::model_product_analytics_server_side_event_item::ProductAnalyticsServerSideEventItem; +pub mod model_product_analytics_server_side_event_item_account; +pub use self::model_product_analytics_server_side_event_item_account::ProductAnalyticsServerSideEventItemAccount; +pub mod model_product_analytics_server_side_event_item_application; +pub use self::model_product_analytics_server_side_event_item_application::ProductAnalyticsServerSideEventItemApplication; +pub mod model_product_analytics_server_side_event_item_event; +pub use self::model_product_analytics_server_side_event_item_event::ProductAnalyticsServerSideEventItemEvent; +pub mod model_product_analytics_server_side_event_item_session; +pub use self::model_product_analytics_server_side_event_item_session::ProductAnalyticsServerSideEventItemSession; +pub mod model_product_analytics_server_side_event_item_type; +pub use self::model_product_analytics_server_side_event_item_type::ProductAnalyticsServerSideEventItemType; +pub mod model_product_analytics_server_side_event_item_usr; +pub use self::model_product_analytics_server_side_event_item_usr::ProductAnalyticsServerSideEventItemUsr; +pub mod model_product_analytics_server_side_event_errors; +pub use self::model_product_analytics_server_side_event_errors::ProductAnalyticsServerSideEventErrors; +pub mod model_product_analytics_server_side_event_error; +pub use self::model_product_analytics_server_side_event_error::ProductAnalyticsServerSideEventError; pub mod model_facet_info_request; pub use self::model_facet_info_request::FacetInfoRequest; pub mod model_facet_info_request_data; diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_error.rs b/src/datadogV2/model/model_product_analytics_server_side_event_error.rs new file mode 100644 index 000000000..f061f3561 --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_error.rs @@ -0,0 +1,139 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// Error details. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventError { + /// Error message. + #[serde(rename = "detail")] + pub detail: Option, + /// Error code. + #[serde(rename = "status")] + pub status: Option, + /// Error title. + #[serde(rename = "title")] + pub title: Option, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventError { + pub fn new() -> ProductAnalyticsServerSideEventError { + ProductAnalyticsServerSideEventError { + detail: None, + status: None, + title: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn detail(mut self, value: String) -> Self { + self.detail = Some(value); + self + } + + pub fn status(mut self, value: String) -> Self { + self.status = Some(value); + self + } + + pub fn title(mut self, value: String) -> Self { + self.title = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for ProductAnalyticsServerSideEventError { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventError { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventErrorVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventErrorVisitor { + type Value = ProductAnalyticsServerSideEventError; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut detail: Option = None; + let mut status: Option = None; + let mut title: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "detail" => { + if v.is_null() { + continue; + } + detail = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "status" => { + if v.is_null() { + continue; + } + status = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "title" => { + if v.is_null() { + continue; + } + title = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + + let content = ProductAnalyticsServerSideEventError { + detail, + status, + title, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventErrorVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_errors.rs b/src/datadogV2/model/model_product_analytics_server_side_event_errors.rs new file mode 100644 index 000000000..0326913e3 --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_errors.rs @@ -0,0 +1,110 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// Error response. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventErrors { + /// Structured errors. + #[serde(rename = "errors")] + pub errors: Option>, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventErrors { + pub fn new() -> ProductAnalyticsServerSideEventErrors { + ProductAnalyticsServerSideEventErrors { + errors: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn errors( + mut self, + value: Vec, + ) -> Self { + self.errors = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for ProductAnalyticsServerSideEventErrors { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventErrors { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventErrorsVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventErrorsVisitor { + type Value = ProductAnalyticsServerSideEventErrors; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut errors: Option< + Vec, + > = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "errors" => { + if v.is_null() { + continue; + } + errors = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + + let content = ProductAnalyticsServerSideEventErrors { + errors, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventErrorsVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item.rs new file mode 100644 index 000000000..353e668ed --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item.rs @@ -0,0 +1,198 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// A Product Analytics server-side event. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventItem { + /// The account linked to your event. + #[serde(rename = "account")] + pub account: Option, + /// The application in which you want to send your events. + #[serde(rename = "application")] + pub application: crate::datadogV2::model::ProductAnalyticsServerSideEventItemApplication, + /// Fields used for the event. + #[serde(rename = "event")] + pub event: crate::datadogV2::model::ProductAnalyticsServerSideEventItemEvent, + /// The session linked to your event. + #[serde(rename = "session")] + pub session: Option, + /// The type of Product Analytics event. Must be `server` for server-side events. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::ProductAnalyticsServerSideEventItemType, + /// The user linked to your event. + #[serde(rename = "usr")] + pub usr: Option, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventItem { + pub fn new( + application: crate::datadogV2::model::ProductAnalyticsServerSideEventItemApplication, + event: crate::datadogV2::model::ProductAnalyticsServerSideEventItemEvent, + type_: crate::datadogV2::model::ProductAnalyticsServerSideEventItemType, + ) -> ProductAnalyticsServerSideEventItem { + ProductAnalyticsServerSideEventItem { + account: None, + application, + event, + session: None, + type_, + usr: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn account( + mut self, + value: crate::datadogV2::model::ProductAnalyticsServerSideEventItemAccount, + ) -> Self { + self.account = Some(value); + self + } + + pub fn session( + mut self, + value: crate::datadogV2::model::ProductAnalyticsServerSideEventItemSession, + ) -> Self { + self.session = Some(value); + self + } + + pub fn usr( + mut self, + value: crate::datadogV2::model::ProductAnalyticsServerSideEventItemUsr, + ) -> Self { + self.usr = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItem { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventItemVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventItemVisitor { + type Value = ProductAnalyticsServerSideEventItem; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut account: Option< + crate::datadogV2::model::ProductAnalyticsServerSideEventItemAccount, + > = None; + let mut application: Option< + crate::datadogV2::model::ProductAnalyticsServerSideEventItemApplication, + > = None; + let mut event: Option< + crate::datadogV2::model::ProductAnalyticsServerSideEventItemEvent, + > = None; + let mut session: Option< + crate::datadogV2::model::ProductAnalyticsServerSideEventItemSession, + > = None; + let mut type_: Option< + crate::datadogV2::model::ProductAnalyticsServerSideEventItemType, + > = None; + let mut usr: Option< + crate::datadogV2::model::ProductAnalyticsServerSideEventItemUsr, + > = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "account" => { + if v.is_null() { + continue; + } + account = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "application" => { + application = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "event" => { + event = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "session" => { + if v.is_null() { + continue; + } + session = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::ProductAnalyticsServerSideEventItemType::UnparsedObject(_type_) => { + _unparsed = true; + }, + _ => {} + } + } + } + "usr" => { + if v.is_null() { + continue; + } + usr = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let application = + application.ok_or_else(|| M::Error::missing_field("application"))?; + let event = event.ok_or_else(|| M::Error::missing_field("event"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = ProductAnalyticsServerSideEventItem { + account, + application, + event, + session, + type_, + usr, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventItemVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item_account.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item_account.rs new file mode 100644 index 000000000..d4f5d2497 --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item_account.rs @@ -0,0 +1,92 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// The account linked to your event. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventItemAccount { + /// The account ID used in Datadog. + #[serde(rename = "id")] + pub id: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventItemAccount { + pub fn new(id: String) -> ProductAnalyticsServerSideEventItemAccount { + ProductAnalyticsServerSideEventItemAccount { + id, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItemAccount { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventItemAccountVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventItemAccountVisitor { + type Value = ProductAnalyticsServerSideEventItemAccount; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut id: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + + let content = ProductAnalyticsServerSideEventItemAccount { + id, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventItemAccountVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item_application.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item_application.rs new file mode 100644 index 000000000..02ea21c4a --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item_application.rs @@ -0,0 +1,93 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// The application in which you want to send your events. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventItemApplication { + /// The application ID of your application. It can be found in your + /// [application management page](). + #[serde(rename = "id")] + pub id: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventItemApplication { + pub fn new(id: String) -> ProductAnalyticsServerSideEventItemApplication { + ProductAnalyticsServerSideEventItemApplication { + id, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItemApplication { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventItemApplicationVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventItemApplicationVisitor { + type Value = ProductAnalyticsServerSideEventItemApplication; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut id: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + + let content = ProductAnalyticsServerSideEventItemApplication { + id, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventItemApplicationVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item_event.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item_event.rs new file mode 100644 index 000000000..d915286b8 --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item_event.rs @@ -0,0 +1,92 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// Fields used for the event. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventItemEvent { + /// The name of your event, which is used for search in the same way as view or action names. + #[serde(rename = "name")] + pub name: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventItemEvent { + pub fn new(name: String) -> ProductAnalyticsServerSideEventItemEvent { + ProductAnalyticsServerSideEventItemEvent { + name, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItemEvent { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventItemEventVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventItemEventVisitor { + type Value = ProductAnalyticsServerSideEventItemEvent; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut name: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "name" => { + name = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let name = name.ok_or_else(|| M::Error::missing_field("name"))?; + + let content = ProductAnalyticsServerSideEventItemEvent { + name, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventItemEventVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item_session.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item_session.rs new file mode 100644 index 000000000..da362c15d --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item_session.rs @@ -0,0 +1,92 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// The session linked to your event. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventItemSession { + /// The session ID captured by the SDK. + #[serde(rename = "id")] + pub id: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventItemSession { + pub fn new(id: String) -> ProductAnalyticsServerSideEventItemSession { + ProductAnalyticsServerSideEventItemSession { + id, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItemSession { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventItemSessionVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventItemSessionVisitor { + type Value = ProductAnalyticsServerSideEventItemSession; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut id: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + + let content = ProductAnalyticsServerSideEventItemSession { + id, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventItemSessionVisitor) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item_type.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item_type.rs new file mode 100644 index 000000000..315961384 --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item_type.rs @@ -0,0 +1,48 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ProductAnalyticsServerSideEventItemType { + SERVER, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for ProductAnalyticsServerSideEventItemType { + fn to_string(&self) -> String { + match self { + Self::SERVER => String::from("server"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for ProductAnalyticsServerSideEventItemType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + _ => serializer.serialize_str(self.to_string().as_str()), + } + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItemType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "server" => Self::SERVER, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_product_analytics_server_side_event_item_usr.rs b/src/datadogV2/model/model_product_analytics_server_side_event_item_usr.rs new file mode 100644 index 000000000..6e69ce4ab --- /dev/null +++ b/src/datadogV2/model/model_product_analytics_server_side_event_item_usr.rs @@ -0,0 +1,92 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// The user linked to your event. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct ProductAnalyticsServerSideEventItemUsr { + /// The user ID used in Datadog. + #[serde(rename = "id")] + pub id: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl ProductAnalyticsServerSideEventItemUsr { + pub fn new(id: String) -> ProductAnalyticsServerSideEventItemUsr { + ProductAnalyticsServerSideEventItemUsr { + id, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for ProductAnalyticsServerSideEventItemUsr { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ProductAnalyticsServerSideEventItemUsrVisitor; + impl<'a> Visitor<'a> for ProductAnalyticsServerSideEventItemUsrVisitor { + type Value = ProductAnalyticsServerSideEventItemUsr; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut id: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + + let content = ProductAnalyticsServerSideEventItemUsr { + id, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(ProductAnalyticsServerSideEventItemUsrVisitor) + } +} diff --git a/tests/scenarios/features/v2/product_analytics.feature b/tests/scenarios/features/v2/product_analytics.feature new file mode 100644 index 000000000..a915c2130 --- /dev/null +++ b/tests/scenarios/features/v2/product_analytics.feature @@ -0,0 +1,35 @@ +@endpoint(product-analytics) @endpoint(product-analytics-v2) +Feature: Product Analytics + Send server-side events to Product Analytics. Server-Side Events Ingestion + allows you to collect custom events from any server-side source, and + retains events for 15 months. Server-side events are helpful for + understanding causes of a funnel drop-off which are external to the + client-side (for example, payment processing error). See the [Product + Analytics page](https://docs.datadoghq.com/product_analytics/) for more + information. + + Background: + Given a valid "apiKeyAuth" key in the system + And an instance of "ProductAnalytics" API + And new "SubmitProductAnalyticsEvent" request + And body with value {"account": {"id": "account-67890"}, "application": {"id": "123abcde-123a-123b-1234-123456789abc"}, "event": {"name": "payment.processed"}, "session": {"id": "session-abcdef"}, "type": "server", "usr": {"id": "user-12345"}} + + @generated @skip @team:DataDog/product-analytics-backend + Scenario: Send server-side events returns "Bad Request" response + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/product-analytics-backend + Scenario: Send server-side events returns "Payload Too Large" response + When the request is sent + Then the response status is 413 Payload Too Large + + @generated @skip @team:DataDog/product-analytics-backend + Scenario: Send server-side events returns "Request Timeout" response + When the request is sent + Then the response status is 408 Request Timeout + + @generated @skip @team:DataDog/product-analytics-backend + Scenario: Send server-side events returns "Request accepted for processing (always 202 empty JSON)." response + When the request is sent + Then the response status is 202 Request accepted for processing (always 202 empty JSON). diff --git a/tests/scenarios/features/v2/undo.json b/tests/scenarios/features/v2/undo.json index eb43f26db..0867c10cd 100644 --- a/tests/scenarios/features/v2/undo.json +++ b/tests/scenarios/features/v2/undo.json @@ -3133,6 +3133,12 @@ "type": "safe" } }, + "SubmitProductAnalyticsEvent": { + "tag": "Product Analytics", + "undo": { + "type": "safe" + } + }, "GetAccountFacetInfo": { "tag": "Rum Audience Management", "undo": { diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index 312f0d588..555291ee6 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -126,6 +126,7 @@ pub struct ApiInstances { pub v2_api_roles: Option, pub v2_api_powerpack: Option, pub v2_api_processes: Option, + pub v2_api_product_analytics: Option, pub v2_api_rum_audience_management: Option, pub v2_api_reference_tables: Option, @@ -846,6 +847,14 @@ pub fn initialize_api_instance(world: &mut DatadogWorld, api: String) { ), ); } + "ProductAnalytics" => { + world.api_instances.v2_api_product_analytics = Some( + datadogV2::api_product_analytics::ProductAnalyticsAPI::with_client_and_config( + world.config.clone(), + world.http_client.as_ref().unwrap().clone(), + ), + ); + } "RumAudienceManagement" => { world.api_instances.v2_api_rum_audience_management = Some(datadogV2::api_rum_audience_management::RumAudienceManagementAPI::with_client_and_config( world.config.clone(), @@ -3926,6 +3935,10 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { "v2.ListProcessesWithPagination".into(), test_v2_list_processes_with_pagination, ); + world.function_mappings.insert( + "v2.SubmitProductAnalyticsEvent".into(), + test_v2_submit_product_analytics_event, + ); world.function_mappings.insert( "v2.GetAccountFacetInfo".into(), test_v2_get_account_facet_info, @@ -30041,6 +30054,34 @@ fn test_v2_list_processes_with_pagination( world.response.code = 200; } +fn test_v2_submit_product_analytics_event( + world: &mut DatadogWorld, + _parameters: &HashMap, +) { + let api = world + .api_instances + .v2_api_product_analytics + .as_ref() + .expect("api instance not found"); + let body = serde_json::from_value(_parameters.get("body").unwrap().clone()).unwrap(); + let response = match block_on(api.submit_product_analytics_event_with_http_info(body)) { + Ok(response) => response, + Err(error) => { + return match error { + Error::ResponseError(e) => { + world.response.code = e.status.as_u16(); + if let Some(entity) = e.entity { + world.response.object = serde_json::to_value(entity).unwrap(); + } + } + _ => panic!("error parsing response: {error}"), + }; + } + }; + world.response.object = serde_json::to_value(response.entity).unwrap(); + world.response.code = response.status.as_u16(); +} + fn test_v2_get_account_facet_info(world: &mut DatadogWorld, _parameters: &HashMap) { let api = world .api_instances