manchenkoff / openapi3-parser

OpenAPI 3 parser to use a specification inside of the code in your projects
https://pypi.org/project/openapi3-parser/
MIT License
61 stars 33 forks source link

[Feature] Loosen up casting/validation logic (enforced by enums) #40

Closed sergei-maertens closed 2 years ago

sergei-maertens commented 2 years ago

What is a problem?

I have some API schemas that use less-obvious (valid) OpenAPI constructs that are not supported by this library because of the hardcoded strictness in the openapi_parser.enumeration module.

For example - error responses follow RFC 7807, which results in the responses having a application/problem+json Content Type - which is not present in the ContentType enum. As far as I'm aware, using custom content types is supported in OpenAPI 3 (and the underlying prance library also doesn't seem to complain about this).

Another example is the type: string and format: duration specification - only date-time is present in the StringFormat, while duration maps to the ISO8601 durations. The OAS 3 spec explicitly mentions that format is an open value:

Primitives have an optional modifier property: format. OAS uses several known formats to define in fine detail the data type being used. However, to support documentation needs, the format property is an open string-valued property, and can have any value. Formats such as "email", "uuid", and so on, MAY be used even though undefined by this specification.

Describe the solution you'd like

Values not present in the enums should not raise exceptions, but be silently accepted _as long as they comply with the OpenAPI 3 specification. This may even remove the need completely for the enums.

Alternatively, a register-approach for these enums could be useful so that library-users can add their own (common) definitions, as this information can help in emitting python type hints and down the road maybe even in generating API clients with the correct casting operations (e.g. formatting a python timedelta or relativedelta into an ISO8601 string during serialization).

Describe alternatives you've considered

Currently I can use aenum to extend the enums and add extra formats, but this is not sustainable as it only works for formats/content-types present in the API schema's to parse. In building a more generic tool to compare equivalency of mulitple API specs, this should be able to handle any unseen-before specifications thrown at it.

Additional context

I'm investigation options for OpenAPI-parsing libraries so that I can build a tool to compare equivalency. Your use of dataclasses and dedicated python types for API schema objects is well suited to that and I'd prefer using that over having to process the python dicts/lists from raw underlying data.

manchenkoff commented 2 years ago

Hey @sergei-maertens, thanks for your suggestion. Actually, I agree with you that it's could be incorrect to prevent allowed values by the specification. Those enumerations were created according to basic Open API specifications and don't include all possible values.

Since changes you suggested might break backward compatibility, I'd suggest using optional parser parameter which can be used for disabling strict enumerations like parse(strict_enum=False). So, if you have time or desire, feel free to open PR with these changes.

Btw, I will re-think this feature for the next major release accordingly.

sergei-maertens commented 2 years ago

For now I was able to work around it and build on top of your parser by defining a custom _create_parser function which uses builders with overridden behaviour - see https://github.com/sergei-maertens/openapi-tools/blob/main/openapi_tools/parser/builders.py#L31 for example. I'm using dataclasses to wrap around the strings so that I can later on implement loose comparison semantics (rather than just casting to string directly), so that could be a pattern that's interesting for your next major release :-)

I shall draft up a PR!