summaryrefslogtreecommitdiffstats
path: root/website/content/platform/developer_guide/validators.mdx
diff options
context:
space:
mode:
Diffstat (limited to 'website/content/platform/developer_guide/validators.mdx')
-rw-r--r--website/content/platform/developer_guide/validators.mdx119
1 files changed, 119 insertions, 0 deletions
diff --git a/website/content/platform/developer_guide/validators.mdx b/website/content/platform/developer_guide/validators.mdx
new file mode 100644
index 00000000000..71a9c601b07
--- /dev/null
+++ b/website/content/platform/developer_guide/validators.mdx
@@ -0,0 +1,119 @@
+---
+title: Validators
+sidebar_position: 9
+description: This guide provides detailed instructions on how and where validators should be used.
+keywords:
+- OpenBB Platform
+- Data point addition
+- Provider creation
+- Query parameters
+- Data output models
+- Fetcher class
+- validator
+- field
+- param
+- Fast API
+---
+
+import HeadTitle from '@site/src/components/General/HeadTitle.tsx';
+
+<HeadTitle title="Validators - Developer Guidelines - Development | OpenBB Platform Docs" />
+
+Both QueryParams and Data models can benefit from the tactical use of Pydantic validators.
+This page will outline some of the key scenarios where they are deployed.
+
+Overall, they assist with enforcing Fast API compliance for both inputs and outputs,
+and they work in the final stage of transformation immediately before output.
+
+## Why Use Validators?
+
+Some situations where they are used include:
+
+- Transform, conform, or otherwise alter the entered query parameter or returned data value.
+- A query parameter or data field is a date.
+- A query parameter requires a dynamic default state.
+- Normalizing percent values.
+- Cleaning NaN values.
+
+## Examples
+
+The items to import from the Pydantic library are:
+
+```python
+from pydantic import field_validator, model_validator
+```
+
+<details>
+<summary mdxType="summary">Parsing Dates</summary>
+
+Providers will format dates in a number of ways. OpenBB uses YYYY-MM-DD as the standard convention, for both inputs and outputs.
+
+Outputs are a `datetime` object or JSON serlialized string. Validators are used to parse the date from the specific format.
+This example is used within a provider's `Data` model.
+
+```python
+@field_validator("last_trade_timestamp", mode="before", check_fields=False)
+@classmethod
+def parse_timestamp(cls, v):
+ """Parse a Unix timestamp."""
+ return datetime.fromtimestamp(v)
+```
+
+</details>
+
+<details>
+<summary mdxType="summary">Normalize Percent Values</summary>
+
+At the provider level, we want to standardize the way values representing a percent are returned.
+
+It is our intention to ensure those values are ready-to-consume by formulas without conversion.
+This example would be used within a provider's `Data` model.
+
+```python
+@field_validator("change_percent", mode="before", check_fields=False)
+@classmethod
+def normalize_percent(cls, v):
+ """Normalize the percent."""
+ return v / 100 if v else None
+```
+
+</details>
+
+<details>
+<summary mdxType="summary">Dynamic Default Date</summary>
+
+It might be desirable to have a default date parameter that is not static. To allow this, we must set the default parameter value as `None`, and use the `model_validator`. This example is for the `QueryParams`.
+
+```python
+@model_validator(mode="before")
+@classmethod
+def validate_dates(cls, values) -> dict:
+ """Validate the query parameters."""
+ if values.get("start_date") is None:
+ values["start_date"] = (datetime.now() - timedelta(days=90)).date()
+ if values.get("end_date") is None:
+ values["end_date"] = datetime.now().date()
+ return values
+```
+
+</details>
+
+<details>
+<summary mdxType="summary">Replace 0s With None</summary>
+
+Sometimes values are returned as a `0` when they should really be a `null`.
+This example looks at the entire `Data` model, but could easily be adapted to use on individual fields.
+
+```python
+@model_validator(mode="before")
+@classmethod
+def replace_zero(cls, values):
+ """Check for zero values and replace with None."""
+ return (
+ {k: None if v == 0 else v for k, v in values.items()}
+ if isinstance(values, dict)
+ else values
+ )
+```
+
+</details>