firecrawl_sdk/
document.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[cfg(feature = "mcp-tool")]
5use schemars::JsonSchema;
6
7#[serde_with::skip_serializing_none]
8#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
9#[cfg_attr(feature = "mcp-tool", derive(JsonSchema))]
10#[serde(rename_all = "camelCase")]
11pub struct DocumentMetadata {
12 #[serde(rename = "sourceURL")]
14 pub source_url: String,
15 pub status_code: u16,
16 pub error: Option<String>,
17
18 #[serde(default)]
20 #[serde(deserialize_with = "deserialize_string_or_vec")]
21 pub title: Option<String>,
22
23 #[serde(default)]
24 #[serde(deserialize_with = "deserialize_string_or_vec")]
25 pub description: Option<String>,
26
27 #[serde(default)]
28 #[serde(deserialize_with = "deserialize_string_or_vec")]
29 pub language: Option<String>,
30
31 #[serde(flatten)]
33 pub additional_fields: std::collections::HashMap<String, Value>,
34}
35
36fn deserialize_string_or_vec<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
38where
39 D: serde::Deserializer<'de>,
40{
41 struct StringOrVec;
42
43 impl<'de> serde::de::Visitor<'de> for StringOrVec {
44 type Value = Option<String>;
45
46 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
47 formatter.write_str("string or array of strings")
48 }
49
50 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
51 where
52 E: serde::de::Error,
53 {
54 Ok(Some(value.to_string()))
55 }
56
57 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
58 where
59 E: serde::de::Error,
60 {
61 Ok(Some(value))
62 }
63
64 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
65 where
66 A: serde::de::SeqAccess<'de>,
67 {
68 if let Some(first) = seq.next_element::<String>()? {
70 return Ok(Some(first));
71 }
72 Ok(None)
73 }
74
75 fn visit_none<E>(self) -> Result<Self::Value, E>
76 where
77 E: serde::de::Error,
78 {
79 Ok(None)
80 }
81
82 fn visit_unit<E>(self) -> Result<Self::Value, E>
83 where
84 E: serde::de::Error,
85 {
86 Ok(None)
87 }
88 }
89
90 deserializer.deserialize_any(StringOrVec)
91}
92
93#[serde_with::skip_serializing_none]
95#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
96#[serde(rename_all = "camelCase")]
97pub struct ScrapeActionResult {
98 pub url: String,
100 pub html: String,
102}
103
104#[serde_with::skip_serializing_none]
106#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
107#[serde(rename_all = "camelCase")]
108pub struct JavaScriptReturnValue {
109 #[serde(rename = "type")]
111 pub value_type: String,
112 pub value: Value,
114}
115
116#[serde_with::skip_serializing_none]
118#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
119#[serde(rename_all = "camelCase")]
120pub struct ActionResults {
121 pub screenshots: Option<Vec<String>>,
123 pub scrapes: Option<Vec<ScrapeActionResult>>,
125 pub javascript_returns: Option<Vec<JavaScriptReturnValue>>,
127}
128
129#[serde_with::skip_serializing_none]
130#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
131#[serde(rename_all = "camelCase")]
132pub struct Document {
133 pub markdown: Option<String>,
135
136 pub html: Option<String>,
140
141 pub raw_html: Option<String>,
145
146 pub screenshot: Option<String>,
148
149 pub links: Option<Vec<String>>,
151
152 #[serde(alias = "llm_extraction")]
155 pub extract: Option<Value>,
156
157 pub json: Option<Value>,
160
161 pub actions: Option<ActionResults>,
163
164 pub metadata: DocumentMetadata,
166
167 pub warning: Option<String>,
170}