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

[Question] Skip validation for real? #291

Open
TheMiloAnderson opened this issue Mar 17, 2023 · 8 comments
Open

[Question] Skip validation for real? #291

TheMiloAnderson opened this issue Mar 17, 2023 · 8 comments

Comments

@TheMiloAnderson
Copy link

The validation is a great feature, but I just want an OpenAPI spec generator for Flask+Pydantic & would prefer to be explicit about the validation & error responses in the body of the view function.

I added skip_validation=True to the decorator as per the README, but it doesn't seem to affect anything; at least the FlaskPlugin request_validation method proceeds unaffected. Have I misunderstood something?

@yedpodtrzitko
Copy link
Collaborator

hi, can you please provide more details? Is it a request or a response validation you intend to skip? Can you show some minimal-reproducible example where it's not working as intended?

@TheMiloAnderson
Copy link
Author

Ideally I'd like to have the option to skip both request & response validation.

I tried to strip it down as much as possible. I've got a view function like this:

from spectree import SpecTree
from pydantic import BaseModel
from spectree import Response
from flask.views import MethodView
from flask import jsonify

spec = SpecTree("flask", title="Settings Service", mode="strict")

class TestModel(BaseModel):
    foo: str
    bar: int

class TestView(MethodView):
    @spec.validate(json=TestModel, resp=Response(HTTP_200=TestModel), skip_validation=True)
    def post(self, service_name):
        return jsonify({"foo": "zot", "bar": 0})

Then I import the view into a blueprint.py file like this:

from flask import Blueprint
from settings.views.v2.test_view import TestView

v2_blueprint = Blueprint("v2_views", __name__)

v2_blueprint.add_url_rule(
    "/<string:service_name>/district/setting_definition/",
    view_func=TestView.as_view("district_setting_definition_view"), methods=['POST']
)

Then app.py imports & registers the blueprint:

from flask import Flask
from settings.views.v2 import v2_blueprint

def create_app():
    settings_app = Flask('settings')
    settings_app.register_blueprint(v2_blueprint, url_prefix="/v2")
    return settings_app

The generated spec looks good so I assume I have done this correctly. However the spec includes this 422 response:

[
  {
    "ctx": {},
    "loc": [
      "string"
    ],
    "msg": "string",
    "type": "string"
  }
]

This test passes, as I would expect it to:

    def test_skip_verify(self):
        response = self.json_post(
            "/v2/%s/district/setting_definition/" % self.service_name,
            json_data={"foo": "hey", "bar": 10},
        )
        self.assertEqual(response.status_code, 200)

However if I change it to:

    def test_skip_verify(self):
        response = self.json_post(
            "/v2/%s/district/setting_definition/" % self.service_name,
            json_data={"something-completely-different": "hey"},
        )
        self.assertEqual(response.status_code, 200)

...it fails with a 422:

b'[{"loc":["foo"],"msg":"field required","type":"value_error.missing"},{"loc":["bar"],"msg":"field required","type":"value_error.missing"}]\n'

@kemingy
Copy link
Member

kemingy commented Mar 18, 2023

So skip here means skip the response type validation. Not the request validation.

May I know why you don't want to have the request validation?

@TheMiloAnderson
Copy link
Author

That makes a lot more sense, thank you for clarifying it only skips the response validation.

Skipping the request validation is not a hill I will die on. On reflection I think it's fine as-is -- I was wary about coupling API docs with validation, wanted to stay flexible & keep the code simple & explicit & easily traceable. I'm testing this out for a microservice that is already very complex. But on second thought the validation decorator tells future devs everything they need to know, and it seems likely we will always want at least simple type checking when there is request json.

I've run into a new problem: Although the API tests behave as expected, when I actually hit the endpoint with Postman the request json doesn't get validated. The response validation does work, but no matter what I pass in the request, there is no error and the Context object is always empty: Context(query=None, json=None, form=None, headers=None, cookies=None)

Do you have any idea what could cause this?

@yedpodtrzitko
Copy link
Collaborator

most likely you're not sending content-type: application/json header there

@TheMiloAnderson
Copy link
Author

facepalm yeah that was it. Thanks a million, guys.

BTW would you accept a PR to rename skip_validation to skip_response_validation? Might save others the confusion I went through

@kemingy
Copy link
Member

kemingy commented Mar 22, 2023

BTW would you accept a PR to rename skip_validation to skip_response_validation? Might save others the confusion I went through

I guess we can add some documentation to make it more clearly. Changing the name may break some users. What do you think?

@TheMiloAnderson
Copy link
Author

Sure! I can help with that. Sorry, been busy.

BTW FWIW there was a lot of pushback on my team against using spectree, concerns about adopting a less-well-established library into critical infrastructure. It would have helped a lot to ease their concerns if it were possible to fully disable validation & just use it for generating docs. I hope you'll consider adding this option in the future.

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

3 participants