Package: openapydantic
Openapydanticopenapispecification validator based onpydantic.Python version support3.8+Openapi versions support❌ 2.0🟠 3.0.0🟠 3.0.1✅ 3.0.2❌ 3.0.3❌ 3.1.0Openapi versions are retrocompatibles (except for major version).So 3.0.2 specification should be able to handle 3.0.0 and 3.0.1 data.Unit tests handle this case (3.0.2 object automatically try to load previous version fixtures).InstallationDepending on your preference...pip install openapydantic...or...poetry add openapydanticBasic usageApi loaderOpenapydantic provide an openapi specification (a.k.a "swagger file") loader.This loader returns a pydantic model so you can work with your specification like a common pydantic python object.For each openapi specification version, there's a dedicated python class.The loader can either automatically determine the class to provide...importasyncioimportopenapydanticapi=asyncio.run(openapydantic.load_api(file_path="openapi-spec.yaml",),)print(api.info)# if my openapi version is "3.0.2", 'api' is an instance of OpenApi302# if the version is not implemented, it will crash... or you can also specify a specific version.It may be useful for backward compatibility (for eg: create an OpenApi302 object using data from an 3.0.1 openapi specfication ).importasyncioimportopenapydanticOpenApiVersion=openapydantic.OpenApiVersionapi=asyncio.run(openapydantic.load_api(file_path="openapi-spec-3-0-1.yaml",version=OpenApiVersion.v3_0_2),)# Here ,'api' is an OpenApi302 object, event if you send an 3.0.1 spec.print(api.openapi)>>3.0.1# version in the spec fileprint(api.__version__)>>3.0.2# openapi version supported for the object classReference interpolationOpenapydantic will interpolate openapi references.If your api looks like this:# my-api.yamlopenapi:3.0.2info:version:"1.0.0"title:Examplepaths:/user:get:summary:Get userresponses:"200":description:successful operationcontent:application/json:schema:$ref:"#/components/schemas/User"components:schemas:User:type:objectproperties:id:type:integerformat:int64name:type:stringexample:"JohnDoe"Once loaded, it will be usable like if it was ...openapi:3.0.2info:version:"1.0.0"title:Examplepaths:/user:get:summary:Get userresponses:"200":description:successful operationcontent:application/json:schema:type:objectproperties:id:type:integerformat:int64name:type:stringexample:"JohnDoe"And so you will be able to do things like...importasyncioimportopenapydanticapi=asyncio.run(openapydantic.load_api(file_path="my-api.yaml",),)print(api.info)print(api.paths["/user"].get.responses["200"].content["application/json"].schema_.properties["name"].example)>>JohnDoeAs describe in the openapi specification some attributes are fix ('paths', 'content' etc...) and some can be mapping with a free key.Mapping must be accessed like common dict, either by direct key loading, either using .get('key')Note that file reference (e.g: "#/file.yaml" are currently not supported)Reference that reference themself will not be interpolated so ...# my-api.yamlopenapi:3.0.2info:version:"1.0.0"title:Examplepaths:/user:get:summary:Get userresponses:"200":description:successful operationcontent:application/json:schema:$ref:"#/components/schemas/User"components:schemas:User:type:objectproperties:id:type:integerformat:int64name:type:stringexample:"JohnDoe"brother:$ref:"#/components/schemas/User".. will stay the same ...importasyncioimportopenapydanticapi=asyncio.run(openapydantic.load_api(file_path="my-api.yaml",),)print(api.components.schemas["User"].properties["brother"].ref)>>'#/components/schemas/User'Attributes name collisionOpenapi specify some attribute which name are already reserved either by pydantic,either by the python language itself.To access these attributes, you must use the Openapydantic specific nameAttribute nameOpenapydantic specific nameschemaschema_inin_notnot_e.g:print(api.paths["/user"].get.responses["200"].content["application/json"].schema_)Model exportYou can access the original api you provided as a dict using theraw_apiattribute.importasyncioimportopenapydanticapi=asyncio.run(openapydantic.load_api(file_path="my-api.yaml",),)print(api.raw_api)>>{'openapi':'3.0.2','info':{'version':'1.0.0','title':'Example'},'paths':{'/user':{'get':{'summary':'Get user','responses':{'200':{'description':'successful operation','content':{'application/json':{'schema':{'$ref':'#/components/schemas/User'}}}}}}}},'components':{'schemas':{'User':{'type':'object','properties':{'id':{'type':'integer','format':'int64'},'name':{'type':'string','example':'John Doe'}}}}}}You can export your data as json string or as python dict using specific methods:importasyncioimportopenapydanticapi=asyncio.run(openapydantic.load_api(file_path="my-api.yaml",),)print(api.as_clean_json())>>{"openapi":"3.0.2","info":{"title":"Example","version":"1.0.0"},"paths":{"/user":{"get":{"summary":"Get user","responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string","example":"John Doe"}}}}}}}}}}}print(api.as_clean_dict())>{'openapi':<OpenApiVersion.v3_0_2:'3.0.2'>,'info':{'title':'Example','version':'1.0.0'},'paths':{'/user':{'get':{'summary':'Get user','responses':{'200':{'description':'successful operation','content':{'application/json':{'schema':{'type':<JsonType.object_:'object'>,'properties':{'id':{'type':<JsonType.integer:'integer'>,'format':'int64'},'name':{'type':<JsonType.string:'string'>,'example':'John Doe'}}}}}}}}}}}Note that these functions are just wrapper to .dict() and .json() pydantic model with specific parameters.By default, since the references are interpolated, thecomponentsroot key is exclude.If you want to have it in the output, you can set theexclude_componentsparameter to False.importasyncioimportopenapydanticapi=asyncio.run(openapydantic.load_api(file_path="my-api.yaml",),)print(api.as_clean_json(exclude_components=False,),)>>{"components":{"schemas":{"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string","example":"John Doe"}}}}},"openapi":"3.0.2","info":{"title":"Example","version":"1.0.0"},"paths":{"/user":{"get":{"summary":"Get user","responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string","example":"John Doe"}}}}}}}}}},"raw_api":{"openapi":"3.0.2","info":{"version":"1.0.0","title":"Example"},"paths":{"/user":{"get":{"summary":"Get user","responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}}}}}},"components":{"schemas":{"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string","example":"John Doe"}}}}}}}In the same way,theraw_apiattribute is exclude by default.If you want to have it in the output, you can set theexclude_raw_apiparameter to False.