data_for_seo/entity/mod.rs
1//! Response and data models, organized by API domain.
2
3mod ai_optimization;
4mod app_data;
5mod appendix;
6mod backlinks;
7mod business_data;
8mod content_analysis;
9mod content_generation;
10mod dataforseo_labs;
11mod domain_analytics;
12mod keywords_data;
13mod merchant;
14mod on_page;
15mod serp;
16
17pub use ai_optimization::*;
18pub use app_data::*;
19pub use appendix::*;
20pub use backlinks::*;
21pub use business_data::*;
22pub use content_analysis::*;
23pub use content_generation::*;
24pub use dataforseo_labs::*;
25pub use domain_analytics::*;
26pub use keywords_data::*;
27pub use merchant::*;
28pub use on_page::*;
29use serde::{Deserialize, Serialize};
30use serde_json::Value;
31pub use serp::*;
32
33/// Top-level response envelope shared by every DataForSEO endpoint.
34#[derive(Debug, Default, Serialize, Deserialize, Clone)]
35pub struct DataForSeoApiResponseData<R> {
36 /// Current API version.
37 pub version: String,
38 /// General status code of the request; `20000` means "Ok".
39 /// See <https://docs.dataforseo.com/v3/appendix/errors/>.
40 pub status_code: i32,
41 /// Informational message accompanying `status_code`.
42 pub status_message: String,
43 /// Total execution time.
44 pub time: String,
45 /// Total cost of the request in USD.
46 pub cost: f64,
47 /// Number of tasks in the `tasks` array.
48 pub tasks_count: i32,
49 /// Number of tasks that returned an error.
50 pub tasks_error: i32,
51 /// Echo of the `limit` request parameter, where applicable.
52 pub limit: Option<i32>,
53 /// Echo of the `offset` request parameter, where applicable.
54 pub offset: Option<i32>,
55 /// Echo of the `sort` request parameter, where applicable.
56 pub sort: Option<String>,
57 /// Echo of the `include_metadata` request parameter, where applicable.
58 pub include_metadata: Option<bool>,
59 /// Tasks executed within this request.
60 pub tasks: Option<Vec<DataForSeoApiTask<R>>>,
61}
62
63impl<R> DataForSeoApiResponseData<R> {
64 /// All tasks in the response (empty slice when the API returned none).
65 pub fn tasks(&self) -> &[DataForSeoApiTask<R>] {
66 self.tasks.as_deref().unwrap_or_default()
67 }
68
69 /// Consumes the response and returns its tasks.
70 pub fn into_tasks(self) -> Vec<DataForSeoApiTask<R>> {
71 self.tasks.unwrap_or_default()
72 }
73
74 /// Iterates over every result of every task.
75 pub fn results(&self) -> impl Iterator<Item = &R> {
76 self.tasks().iter().flat_map(|task| task.results().iter())
77 }
78
79 /// Consumes the response and returns every result of every task.
80 pub fn into_results(self) -> Vec<R> {
81 self.into_tasks()
82 .into_iter()
83 .flat_map(|task| task.result.unwrap_or_default())
84 .collect()
85 }
86
87 /// First result across all tasks, if any.
88 pub fn first_result(&self) -> Option<&R> {
89 self.results().next()
90 }
91}
92
93/// A single task inside a [`DataForSeoApiResponseData`] envelope.
94#[derive(Debug, Default, Serialize, Deserialize, Clone)]
95pub struct DataForSeoApiTask<R> {
96 /// Unique task identifier in UUID format.
97 pub id: String,
98 /// Task status code; `20000` means "Ok".
99 /// See <https://docs.dataforseo.com/v3/appendix/errors/>.
100 pub status_code: i32,
101 /// Informational message accompanying `status_code`.
102 pub status_message: String,
103 /// Execution time of this task.
104 pub time: String,
105 /// Cost of this task in USD.
106 pub cost: f64,
107 /// URL path segments of the executed function (e.g. `["v3", "serp", ...]`).
108 pub path: Vec<String>,
109 /// Echo of the parameters submitted when the task was created.
110 pub data: Value,
111 /// Results produced by this task.
112 pub result: Option<Vec<R>>,
113}
114
115impl<R> DataForSeoApiTask<R> {
116 /// Results of this task (empty slice when the API returned none).
117 pub fn results(&self) -> &[R] {
118 self.result.as_deref().unwrap_or_default()
119 }
120
121 /// `true` when the task finished successfully (status code `20000`..`29999`).
122 pub fn is_success(&self) -> bool {
123 matches!(self.task_status(), TaskStatus::RequestSuccess(_))
124 }
125
126 /// Classifies the task's `status_code`.
127 /// See <https://docs.dataforseo.com/v3/appendix/errors/>.
128 pub fn task_status(&self) -> TaskStatus {
129 match self.status_code {
130 20000..=29999 => TaskStatus::RequestSuccess(self.status_code),
131 40601 | 40602 => TaskStatus::TaskWaiting(self.status_code),
132 40401 => TaskStatus::TaskNotFound(self.status_code),
133 40202 => TaskStatus::RateLimit(self.status_code),
134 other => TaskStatus::Other(other),
135 }
136 }
137}
138
139/// Classification of a task-level `status_code`.
140#[derive(Debug, Clone)]
141pub enum TaskStatus {
142 /// The task completed successfully (`20000`..`29999`).
143 RequestSuccess(i32),
144 /// The task was created but is not finished yet (`40601`, `40602`).
145 TaskWaiting(i32),
146 /// No task with the given id was found (`40401`).
147 TaskNotFound(i32),
148 /// The rate limit was exceeded (`40202`).
149 RateLimit(i32),
150 /// Any other status code.
151 Other(i32),
152}
153
154/// Common SERP task result wrapper: metadata about the search plus its `items`.
155#[derive(Debug, Default, Serialize, Deserialize, Clone)]
156pub struct SerpApiTaskResult<T> {
157 /// Keyword the search was performed for, UTF-8 decoded.
158 pub keyword: String,
159 /// Search engine type (e.g. `organic`, `maps`).
160 #[serde(rename = "type")]
161 pub search_engine_type: Option<String>,
162 /// Search engine domain the request was made to (e.g. `google.co.jp`).
163 pub se_domain: Option<String>,
164 /// Location code used in the task.
165 pub location_code: i32,
166 /// Language code used in the task.
167 pub language_code: Option<String>,
168 /// Direct URL of the search query.
169 pub check_url: Option<String>,
170 /// Date and time when the result was received, UTC.
171 pub datetime: Option<String>,
172 /// Autocorrection info applied by the search engine, if any.
173 pub spell: Option<Value>,
174 /// Search refinement chips shown in the SERP, if any.
175 pub refinement_chips: Option<SerpApiElementRefinementChips>,
176 /// Element types present in `items` (e.g. `organic`, `people_also_ask`).
177 pub item_types: Option<Vec<String>>,
178 /// Total number of results the search engine reported.
179 pub se_results_count: Option<i64>,
180 /// Number of items returned in `items`.
181 pub items_count: Option<i64>,
182 /// Elements of the search results page.
183 pub items: Option<Vec<T>>,
184}
185
186impl<T> SerpApiTaskResult<T> {
187 /// Items of this result (empty slice when the API returned none).
188 pub fn items(&self) -> &[T] {
189 self.items.as_deref().unwrap_or_default()
190 }
191}