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

Better support for OpenAPI OneOf #261

Closed
mbierma opened this issue Dec 10, 2021 · 1 comment
Closed

Better support for OpenAPI OneOf #261

mbierma opened this issue Dec 10, 2021 · 1 comment

Comments

@mbierma
Copy link
Contributor

mbierma commented Dec 10, 2021

OpenAPI supports the OneOf keyword to allow the combining of schemas. This could be used to allow an endpoint to validate data against one of the specified schemas -- an example from the link is copied below:

paths:
      /pets:
        patch:
          requestBody:
            content:
              application/json:
                schema:
                  oneOf:
                    - $ref: '#/components/schemas/Cat'
                    - $ref: '#/components/schemas/Dog'
          responses:
            '200':
              description: Updated
    components:
      schemas:
        Dog:
          type: object
          properties:
            bark:
              type: boolean
            breed:
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
        Cat:
          type: object
          properties:
            hunts:
              type: boolean
            age:
              type: integer

It appears that OneOf support was added in #18, but I haven't been able to get multiple input schemas to work with Marshmallow -- although I could be missing something.

As initially mentioned in #48 (comment), it would be great if something like this were possible

@mbierma
Copy link
Contributor Author

mbierma commented Jan 6, 2022

Closing this for now, but posting a potential workaround by using oneofschema and a custom FieldConverter:

class FooSchema(marshmallow.Schema):
    foo = marshmallow.fields.String(required=True)

class BarSchema(marshmallow.Schema):
    bar = marshmallow.fields.Integer(required=True)

class MyUberSchema(OneOfSchema):
    type_schemas = {"foo": FooSchema, "bar": BarSchema}

    def get_obj_type(self, obj):
        if isinstance(obj, Foo):
            return "foo"
        elif isinstance(obj, Bar):
            return "bar"
        else:
            raise Exception("Unknown object type: {}".format(obj.__class__.__name__))


class TestSchema(marshmallow.Schema):
    test = marshmallow.fields.Nested(MyUberSchema())


class OneOfConverter(FieldConverter):
    MARSHMALLOW_TYPE = OneOfSchema

    def convert(self, obj, context):
        subschemas = []
        for value in obj.type_schemas.values():
            subschemas.append(context.convert(value(), context))
        return {sw.one_of: subschemas}

response_converter_registry.register_types([OneOfConverter()])
request_body_converter_registry.register_types([OneOfConverter()])

@mbierma mbierma closed this as completed Jan 6, 2022
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

No branches or pull requests

1 participant