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

Limit error response in large union #854

Closed
ashears opened this issue Oct 2, 2019 · 3 comments
Closed

Limit error response in large union #854

ashears opened this issue Oct 2, 2019 · 3 comments
Labels

Comments

@ashears
Copy link
Contributor

ashears commented Oct 2, 2019

Question

I am looking for ways to only see an error in a specific element of a union.

We have some models similar to this example from the docs:

...

class Dessert(BaseModel):
    kind: str

class Pie(Dessert):
    kind: Literal['pie']
    flavor: Optional[str]

class ApplePie(Pie):
    flavor: Literal['apple']

class PumpkinPie(Pie):
    flavor: Literal['pumpkin']

class Meal(BaseModel):
    dessert: Union[ApplePie, PumpkinPie, Pie, Dessert]

...

For the Union in the Meal class, if the input satisfies none of the models, it would throw errors for all. Our use case has over 10 different models that have different fields in the Union and the response is difficult to parse. Each different type is based on a literal string similar to above.
Is there a way to limit/filter errors so that the response is more actionable?

Previously to avoid this, I had one large generic model with Optional field on all elements that were only in some cases. And then custom validators for each element to see whether it was required for this type.

Please complete:

  • OS: macOS, Linux
  • Python version import sys; print(sys.version): 3.7
  • Pydantic version import pydantic; print(pydantic.VERSION): 0.32.2
@dmontagu
Copy link
Contributor

dmontagu commented Oct 2, 2019

Currently, I don't think there is a clean way to validate a union-typed field without seeing all the errors.


I recently put a little effort into building a type called DiscriminatedUnion with the same API as Union (and which is seen exactly the same as a Union by mypy), but which pydantic treats specially:

  • During field type initialization, it would check that:
    • All models in the (discriminated) union have the same value of a config setting indicating the discriminator property
    • All models in the union have that field annotated as a distinct Literal string
  • During parsing, it would:
    • First, look for the discriminator value; if invalid, that would be the only error you'd see
    • If the discriminator is valid, try to parse the payload as the appropriate discriminated model. If parsing fails, you'd only see the one error; otherwise the parsed output would be an object of the discriminated type

I haven't finished the implementation, but I'm convinced it should be possible to implement without too much effort. It should also play nice with the discriminator concept in OpenAPI (though I think most tools have weak support for that, at best).

I'd be curious if there are others interested in this version of the implementation, or if a different API would be preferable.

@ashears
Copy link
Contributor Author

ashears commented Oct 2, 2019

From the perspective of the current codebase I’m working with that implementation would be highly desirable.

I agree that it the swagger may behave weirdly but it already has some issues with anyOf as we discussed on another issue :)

@samuelcolvin
Copy link
Member

I entirely agree that this would be great, see my comment: #619 (comment) and more below that

You can see the bodge I'm using right now for this here.

The reason I haven't worked on descriminator yet was an effort to get version 1 released. Since this should be backwards compatible it should be possible to release in v1.1.

Closing this, if there's more feedback please comment on #619.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants