pyopenapi / pyswagger

An OpenAPI (fka Swagger) client & converter in python, which is type-safe, dynamic, spec-compliant.
MIT License
384 stars 88 forks source link

About swagger specification don't support key "oneOf" and "anyOf" of schema object. #70

Open WillaLuo opened 8 years ago

WillaLuo commented 8 years ago

Hi mission Can pyswagger provide an option for using client to do request with independent input parameter as body data, not according the schema object definitions? Because swagger specification not support "oneOf" and "anyOf" key, it is difficult for us to design schema object for input parameters.

Thanks a lot!

mission-liao commented 8 years ago

Hi, could you clarify your requirement and why would you use "oneOf"/"anyOf"? If you want to bypass those parts, then there is nothing much different between using pyswagger and making raw http requests.

WillaLuo commented 8 years ago

Hi, mission We meet this issue. The request data for rest api of our project is this format, when the "obj_type" is "plan", the content type of array "objects" for request is like this: { "name": "/public/simple_test" "oplans": [ { "obj_type": "plan", "objects": [ { "instances": [ { "imagelist": "/public/dev-vm", } ] } ] } ] }

when the "obj_type" is "plan", the content type of "objects" array for request is like this: { "name": "/public/simple_test" "oplans": [ { "obj_type": "iplist", "objects": [ { "name": "/public/iplist", "dport": 7001, "" } ] } ] }

So that means we need the schema object in swagger definition support any type description of the content of "objects" array. But now, if we design the schema of swagger definition according to the "plan" object_type, pyswagger can't validate the request data of "iplist" correctly. And the reverse is also true. So, we need schema object description support 'anyOf' or "oneOf" the type, but swagger specification not support any type. It only support "allOf". So, we need a workaround for this.

Thanks, Shuang

WillaLuo commented 8 years ago

Hi mission, So we may be need the schema description like this, see the bold text. "Object_instance": { "type": "object", "properties": { "keys":"anytype"// "string" or "array" } } }, "plan":{ "type": "object", "properties": { "object_type": { "type": "string" }, "objects": { "type": "array", "items": { "$ref": "#/definitions/Object_instance" } }
}

    },

"test": { "required": [ "name", "oplans" ], "description": "The request body contains details of create an request", "properties": {
"name": { "type": "string", "description": "The three-part name of the object." }, "oplans": { "items": { "$ref": "#/definitions/plan" }, "type": "array", "description": "List of oplans" } } }

Or can I set nothing in the properties of Object_instance? So, I can give the true data whatever I want.

Thanks, Shuang

mission-liao commented 8 years ago

Hi,

As you already know, Swagger (OpenAPI) wouldn't support "oneOf" or "anyOf" mainly because they encourage deterministic design of APIs.

My suggestion to support "oneOf" or "anyOf" is to set your type as "string" and parse its content by yourself. (Or just make separated APIs for different types).

xpxu commented 8 years ago

@mission-liao In order to process an object which should be defined with 'anyOf', as a workaround, we just define nothing with this object. and then we can bypass the schema check for this object in pyswagger if we find that this object has no details defined in swagger json file.

A sample swagger object is like this:

                "plans": {
                    "items": {
                        "type": "object" # no details defined for this object
                    }, 
                    "type": "array", 
                } 

Add the following code in _model.py. I believe this change has no side-effect.

    def apply_with(self, obj, val, ctx):
        """
        # when obj have no details defined in swagger json file, just pass it directly
        if obj.properties == {}:
            for k in val.iterkeys():
                self[k] = val[k]
            _val = {}

What do you think?

mission-liao commented 8 years ago

Hi, your code-snippet reminds me that you can try "additionalProperties: true"

"definitions":{
  "workaround_anyof":{
    "type":"object",
    "additionalProperties": true
  }
}

Although you can't find this usage on current spec of Swagger, but it was there and pyswagger supports it. Interestingly, the way we support this part is just like the code-snippet you provided. (refer to pyswagger.primitives._model.Model.cleanup).

WillaLuo commented 8 years ago

Hi, mission I see when pyswagger parsing definition file, the additionalProperties default value is true? "additionalProperties" means when I pass additional keys with parameters not defined in schema to the object, pyswagger can handle it, in other ways, the key not appear in the object properties can be validate by pyswagger.primitives._model.Model.cleanup, isn't it? In this way, the key which is any type should not appear in the schema object definition, so it is hard to add description information to this key(how it can be used) when using swagger definition generate document.

mission-liao commented 8 years ago

Hi, @WillaLuo it's based on my wrong understanding about json-schema. According to this issue and current schema.json, the only valid value of additionalProperties is "false", true is forbidden.

There would be no validation performed against those values matched by "additionalProperties: true", that's the only reason why this "backdoor" exists (and why other guys tries to restrict its usage)

I will fix this invalid default value in next release but still allow "additionalProperties: true" to make your workaround possible.