connexion icon indicating copy to clipboard operation
connexion copied to clipboard

Allow customization of validator / Apply defaults in request body

Open phoracek opened this issue 8 years ago • 6 comments

Description

I need Connexion to use default value if a property is missing in request body. Although it is done with URL query, in body 'default' is just for documentation purposes (that is nature of JSON Schema). In order to enforce defaults (as described here https://python-jsonschema.readthedocs.io/en/latest/faq/#why-doesn-t-my-schema-that-has-a-default-property-actually-set-the-default-on-my-instance) I need to overwrite validator used in connexion/decorators/validation.py. It would be even better if Connexion offered defaults enforcement on its own.

Expected bahaviour

  • Access to body validation class in similar way as we have it with Resolver.

OR

  • A flag to set 'defaults enforcement'. When 'defaults' is defined for a non-required property and the property is not passed, default value should be used.

Actual behaviour

We don't have tools for that. When non-required property is not passed, it is not included in data provided for controlled function, even if there are defaults.

Example

...
    post:
      operationId: "controllers.post_foo"
      parameters:
      - in: "body"
        name: "foo"
        required: true
        schema:
          $ref: "#/definitions/Foo"
      responses:
        200:
          description: "OK"
definitions:
  Foo:
    type: "object"
    properties:
      name:
        type: "string"
        default: "BOB"

If -d '{}' was sent, controller should receive {'name': 'BOB'}.

Another example

It should be enough to provide defaults in bottom-most layer.

definitions:
  Foo:
    type: "object"
    default: {}
    properties:
      name:
        type: "object"
        properties:
          first:
            type: "string"
            default: "BOB"
          last:
            type: "string"
            default: "DOE"

If -d '{}' was sent, controller should receive {'name': {'first': 'BOB', 'last': 'DOE'}}.

phoracek avatar Nov 22 '16 14:11 phoracek

I think it could be enough to keep validation_class as Request/ResponseBodyValidator's attribute, RequestBodyValidator as a Operation's attribute and Operation as an Api's attribute (as we do with Resolver). I will take a look at that and hopefully post a draft of needed changes.

phoracek avatar Nov 23 '16 13:11 phoracek

@Ruwann you can use a custom validator since #352. I don't think we should add a flag to add defaults to Connexion. I would close this one if you agree.

RobbeSneyders avatar Jul 24 '21 06:07 RobbeSneyders

Yes, indeed. And there is also an example about how to use default values. However, I was considering adding a flag to enable this behaviour because for query parameters, we do provide the default values:

https://github.com/zalando/connexion/blob/803cf638785223b3a9321c4ad5bbe371a61e38b6/connexion/operations/swagger2.py#L257-L259

https://github.com/zalando/connexion/blob/803cf638785223b3a9321c4ad5bbe371a61e38b6/connexion/operations/openapi.py#L352-L362

Ruwann avatar Jul 24 '21 15:07 Ruwann

When in the code myself, it was this that appears to start with the defaults and update the dict with what the request has.

I'd have to get in there with the debugger/logging to figure out why that doesn't cause the desired behavior... unless you already know.

ddurham2 avatar Mar 16 '22 20:03 ddurham2

I think this only takes the default at the top level of the body and doesn't take into account any nested defaults, https://github.com/spec-first/connexion/blob/87a0fed4dcd164eb779cd11afd838845910b1e32/connexion/operations/openapi.py#L297

RobbeSneyders avatar Mar 16 '22 21:03 RobbeSneyders

FWIW, I just stumbled on a flaw with the approach suggested in some of the other issue related to this (https://github.com/spec-first/connexion/blob/main/examples/swagger2/enforcedefaults/enforcedefaults.py)

If you have a schema with oneOf, the defaults for every type contained within the oneOf will be set. This is because the jsonschema validator invokes the validators for each instance of oneOf, without regard for the provided discriminator value.

I considered seeing if there was a way to strip out the validators which didn't match the provided discrinator, but it appears the the necessary context (mapping the type to the validator) is missing at the point where the validation occurs.

In particular, the schema has nothing like class_name for well-typed objects. With that, I think I could make this work for oneOf polymorphism.

klarose avatar May 11 '22 19:05 klarose

Fixed since https://github.com/spec-first/connexion/pull/1616

RobbeSneyders avatar Feb 18 '23 09:02 RobbeSneyders