Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global models and interface hierarchy #145

Merged
merged 33 commits into from
Dec 13, 2024

Conversation

piercefreeman
Copy link
Owner

@piercefreeman piercefreeman commented Dec 12, 2024

This PR is a pretty significant change to the generation pipeline for TS interfaces. We remove our previous OpenAPI intermediary representation in preference of doing controller introspection manually. This gives us more control to:

  • Provide the full interface composition of controllers & their data models. Each interface is composed of the same superclasses that exist in Python.
  • Refactor common TS components that require some minimum actions/render fields but not the fully instantiated controller. For instance, if some search logic is shared through many different controllers, refactor it into a superclass ControllerBase (python) and a separate frontend component (react).
  • Align the enum key/value naming to the definition in Python.
  • Any module can stably import from "@/_server/controllers" to use enums that might be defined in other controllers and not explicitly imported in our controller.

When all is said and done, this creates a superset of the previous auto-generated files. Client are able to use the previous model definitions if they wish. But they can now optionally interact with all of the classes that are defined in the Python codebase, which furthers our goal of unified typing across frontend and backend.

Migration Guide

Enums

Enums have changed in definition from removing underscores to with proper indentations. This should align with their keys in the original Python. Previously we only had access to the values.

APIException

Exceptions no longer have the "Exception" suffix added to them in the frontend. You should be able to import them with just their exception name.

Required Fields in TS Interfaces

Required fields are a bit hard to reason about when we're thinking about client->server->client syncing. For client->server syncing, if a field has a default in Pydantic, we want it to be optional for clients to send (so it defaults to the server value). But for server->client models that's not true. We know it will be provided within the JSON payload.

We previously tried to be "smart" about this behavior, where if a model is used as a server->client model only we would typehint it as having all values. But once an action uses this same model as a client->server type, the same interface would become optional. This worked for simple cases but resulted in instability for larger projects where one change in usage can cascade through the type definitions. The new version makes this behavior consistent all the time by typehinting these models as optional.

NOTE: If you want to provide default values, but still want the interfaces typehinted as required in TypeScript, you can do so by providing the defaults as part of a model @validation.

Sideeffect response models are unique because they require a concrete
RenderBase of a mounted controller, but the functions themselves can
still be defined at the level of the superclass. Previously we only had
a 1:1 relationship between an action function's metadata and the
response model - but in cases of sideeffects this resulted in a last-win
assignment of the render model to the `sideeffect` property. Our global
controllers typehinted incorrectly in this situation.

This commit solves the issue by registering action render models for
each concrete controller that's registered. Global controllers will do a
union of each identity, whereas the controller owned implementation
itself will only use its more specific sideeffect render.
@piercefreeman piercefreeman merged commit ed92698 into main Dec 13, 2024
20 checks passed
@piercefreeman piercefreeman deleted the feature/shared-superclass-models branch December 13, 2024 03:09
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