Skip to content

Add non-empty String and collection types #39

Description

@emgrav

Issue Description

Most inbound API payloads must reject empty strings and empty collections at the boundary. Current types allow deserialising empty strings/vectors, pushing validation deeper into business logic. We need a consistent, centralised approach so inputs fail fast (e.g. Url-like deserialisation error) and lists are guaranteed non-empty (e.g. via nonempty crate).

Options Comparison

Scope Approach Pros Cons
Deserialisation layer Custom serde validators / newtypes (NonEmptyString, TrimmedNonEmptyString) and #[serde(deserialize_with = ...)] Fails fast at boundary; keeps invariants in types; minimal call-site changes Requires newtype coverage of all string fields; migration effort
Collection enforcement nonempty::NonEmpty<T> for lists in request types Compile-time non-empty guarantee; good serde support; clear invariant in type Type churn on existing structs; iterator ergonomics differ slightly
Mixed validation Smart constructors post-deserialisation Centralised logic; fewer type changes Errors shift deeper; risks partial validation

User Story

As a client or service integrating with our APIs, I want invalid empty strings or empty lists to be rejected immediately at request parsing, so I get clear errors and the system maintains strong invariants.

Acceptance Criteria

  • Provide well-documented newtypes for non-empty strings (e.g. NonEmptyString, optionally TrimmedNonEmptyString) with serde deserialisation that rejects empty/blank input at parse time.
  • Provide a non-empty list type (or re-export/alias of nonempty::NonEmpty) with serde support and ergonomic constructors/iterators for library consumers.
  • Ensure error messages surfaced by deserialisation are explicit and consistent (e.g. “field X must be non-empty”).
  • Add unit tests for the newtypes covering empty/blank strings and empty collections, demonstrating deserialisation failures and success paths.
  • Document usage in Rustdoc: how to annotate fields in consumer DTOs with these types and any helper macros/constructors.

Documentation and References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions