Skip to content

Introduce explicit inputClass, outputClass, dataClass semantics on Metadata#8338

Draft
Cafeine42 wants to merge 1 commit into
api-platform:4.3from
Cafeine42:input-output-idea
Draft

Introduce explicit inputClass, outputClass, dataClass semantics on Metadata#8338
Cafeine42 wants to merge 1 commit into
api-platform:4.3from
Cafeine42:input-output-idea

Conversation

@Cafeine42

Copy link
Copy Markdown
Contributor
Q A
Branch? main for features / current stable version branch for bug fixes
Tickets Closes #7907
License MIT
Doc PR api-platform/docs#...

Introduce explicit inputClass, outputClass, dataClass semantics on Metadata

Context

Metadata::getClass() was used for many distinct purposes: fetching the entity/document class for Doctrine queries, the DTO for serialization, or the API resource class for IRI/routing. All three roles silently collapsed into one method, making it impossible to tell from a call site which concept was intended.

What this PR does

Adds three new methods to Metadata:

  • getApiClass() — semantic alias for getClass(). Signals "I want the API resource class", without changing behaviour.
  • getDataClass() — returns the persistence class (entity, document, Eloquent model) from stateOptions, falling back to getClass(). Implemented via a new DataOptionsInterface on Doctrine ORM/ODM and Eloquent Options.
  • getInputClass() / getOutputClass() — return the DTO class for deserialization/serialization, falling back to getClass() when no explicit DTO is configured. Return null when input: false / output: false.

All ~150 getClass() call sites across the codebase are replaced by whichever of the four is semantically correct.


Open question: can getApiClass() be eliminated?

getApiClass() is currently a pure alias — return $this->class — introduced only to label usages of getClass() that didn't belong to input, output, or data. The question is whether those remaining usages could themselves be replaced.

Looking at the places where getApiClass() is still called:

Use case Why getApiClass() stays necessary
IRI generation (IriConverter) IRIs are registered under the API resource class in the router; using the entity or output DTO would miss the route
Metadata factory lookups (ResourceMetadataCollectionFactory::create()) The metadata registry is keyed on the API resource class
resource_class context key Normalizers and ResourceClassResolver use it to identify which API resource is being processed
SerializerContextBuilder comparison The "is input/output a DTO?" check requires knowing the API class as the baseline: getInputClass() === getApiClass()
force_resource_class (stateOptions without explicit output) Tells the serializer to treat the returned entity as if it were the API resource class
OpenAPI / Hydra documentation Schemas and JSON-LD contexts are indexed by API resource class
Security / access checker Voters are called with the API resource class, not the persistence or output class

In all these cases the API resource class acts as a stable identifier — the thing that ties routing, metadata, IRI templates, and documentation together. It is structurally distinct from what comes in (inputClass), what goes out (outputClass), and what is persisted (dataClass). So getApiClass() cannot be eliminated today; it marks the boundary of the concept rather than a shortcut for one of the other three.

A future step could be to remove getClass() entirely, making getApiClass() the canonical name and forcing any remaining ambiguous callers to be explicit — but that is a separate breaking-change PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant