Skip to content

Commit cc6ea4b

Browse files
committed
docs: reduce clause-gluing dashes in the Pydantic input-validation guide
1 parent 58e6c44 commit cc6ea4b

1 file changed

Lines changed: 7 additions & 7 deletions

File tree

docs/03_guides/11_pydantic.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ An Actor reads its input with <ApiLink to="class/Actor#get_input">`Actor.get_inp
2424
{RawInputExample}
2525
</RunnableCodeBlock>
2626

27-
- There are no type guarantees - `max_results` could just as easily arrive as the string `"10"` or `None`, and you'd only find out when something blows up later.
28-
- There's no validation - nothing stops `max_results` from being `0` or `-5`, or `search_terms` from being empty.
27+
- There are no type guarantees. `max_results` could just as easily arrive as the string `"10"` or `None`, and you'd only find out when something blows up later.
28+
- There's no validation. Nothing stops `max_results` from being `0` or `-5`, or `search_terms` from being empty.
2929
- A typo in a key (`maxResult` instead of `maxResults`) silently falls back to the default instead of failing.
3030
- Defaults are scattered across the codebase, and your editor can't autocomplete the fields or catch mistakes.
3131

@@ -41,15 +41,15 @@ The following Actor declares its input as a Pydantic `BaseModel`, validates the
4141

4242
A few things worth pointing out about the **model**:
4343

44-
- **Aliases bridge the naming conventions.** Apify input fields are conventionally `camelCase` (`maxResults`), while Python attributes are `snake_case` (`max_results`). Since every field follows that convention, `alias_generator=to_camel` derives the camelCase alias for the whole model at once, instead of spelling out `Field(alias=...)` on each field. `populate_by_name=True` lets the model accept either spelling - handy in tests.
44+
- **Aliases bridge the naming conventions.** Apify input fields are conventionally `camelCase` (`maxResults`), while Python attributes are `snake_case` (`max_results`). Since every field follows that convention, `alias_generator=to_camel` derives the camelCase alias for the whole model at once, instead of spelling out `Field(alias=...)` on each field. `populate_by_name=True` lets the model accept either spelling, which is handy in tests.
4545
- **Defaults and `required` fields are explicit.** A field without a default (`search_terms`) is required; one with a default (`max_results`) is optional. There's a single, obvious place where every default lives.
46-
- **Constraints are declarative.** `ge=1, le=100` enforces a numeric range, `min_length=1` rejects an empty list, and `Literal['json', 'csv']` restricts a field to a fixed set of choices - mirroring an `enum` in the input schema.
46+
- **Constraints are declarative.** `ge=1, le=100` enforces a numeric range, `min_length=1` rejects an empty list, and `Literal['json', 'csv']` restricts a field to a fixed set of choices, mirroring an `enum` in the input schema.
4747
- **Custom validators handle the rest.** The `field_validator` normalizes the search terms (trimming whitespace, dropping empties) and rejects input that has nothing left, so the rest of your code never has to repeat those checks.
4848
- **Unknown fields are ignored.** `extra='ignore'` means adding a new field to your input schema won't break an older Actor build that doesn't know about it yet. Use `extra='forbid'` instead if you'd rather reject anything unexpected.
4949

5050
And about the **validation** itself:
5151

52-
- `model_validate` parses the raw dictionary into a typed `ActorInput` instance, filling in defaults and guaranteeing every field is valid - or raising a `ValidationError` describing every problem at once.
52+
- `model_validate` parses the raw dictionary into a typed `ActorInput` instance, filling in defaults and guaranteeing every field is valid, or raising a `ValidationError` describing every problem at once.
5353
- Catching that error, logging a readable summary, and re-raising makes the Actor **fail fast** with a clear explanation right at the start, rather than crashing with an obscure error somewhere deep in the run. Because the body runs inside `async with Actor:`, the re-raised exception automatically marks the run as `FAILED`.
5454
- The error messages refer to the fields by their input-schema aliases. For invalid input like `{"searchTerms": [], "maxResults": 999, "outputFormat": "xml"}`, the log shows exactly what's wrong:
5555

@@ -64,11 +64,11 @@ And about the **validation** itself:
6464
Input should be 'json' or 'csv' ...
6565
```
6666

67-
Once validation passes, the rest of `main` works with `actor_input.search_terms`, `actor_input.max_results`, and `actor_input.output_format` - all correctly typed, with editor autocompletion and static type checking.
67+
Once validation passes, the rest of `main` works with `actor_input.search_terms`, `actor_input.max_results`, and `actor_input.output_format`, all correctly typed, with editor autocompletion and static type checking.
6868

6969
## Relationship to the input schema
7070

71-
Pydantic validation **complements** the Actor's [input schema](https://docs.apify.com/platform/actors/development/input-schema) (`.actor/input_schema.json`) - it doesn't replace it. The two serve different layers:
71+
Pydantic validation **complements** the Actor's [input schema](https://docs.apify.com/platform/actors/development/input-schema) (`.actor/input_schema.json`). It doesn't replace it. The two serve different layers:
7272

7373
- The **input schema** drives the Apify Console form, documents the fields for your users, and lets the platform validate input before the run even starts. Keep declaring your fields there.
7474
- The **Pydantic model** validates the input again *inside your Python code*, where it gives you a typed object, IDE support, and richer rules (normalization, cross-field checks, custom formats) that the input schema can't express. It's also your safety net for runs started programmatically by [another Actor](../concepts/interacting-with-other-actors) or executed [locally](https://docs.apify.com/cli/docs/reference#apify-run), and for keeping the two definitions honest with each other.

0 commit comments

Comments
 (0)