Repository: 0b01001001/spectree (language: python)

Issue:
bug: An empty request is not validated / the content type is not enforced
### Describe the bug

If we send an empty request, the validation will be skipped alltogether!

### To Reproduce

If we take the default example for Flask and run it, we can send an empty request and it will not be validated:
```
curl -X POST http://localhost:8000/api/user
{"text":"it works"}
```

However, if we pass some request data, the validation is applied:
```
curl -X POST http://localhost:8000/api/user -H "Content-Type: application/json" --data '{"name": ""}'
[{"ctx":{"limit_value":2},"loc":["name"],"msg":"ensure this value has at least 2 characters","type":"value_error.any_str.min_length"},{"loc":["age"],"msg":"field required","type":"value_error.missing"}]
```

This is caused because the content type is missing:
```
curl -X POST http://localhost:8000/api/user -H "Content-Type: application/json"
[{"loc":["name"],"msg":"field required","type":"value_error.missing"},{"loc":["age"],"msg":"field required","type":"value_error.missing"}]
```

### Expected behavior

I'd expect the validation to always be enforced, starting by the application type if I only "define" a JSON-type model

### The spectree version

`pip show spectree`
`Version: 1.2.4`

`uname -a`
`Linux 6.1.51`

`Python 3.10.12`

### Additional context

Any ideas?

Thank you!:)


Discussion / hints:

Fix patch:
diff --git a/pyproject.toml b/pyproject.toml
index 9239fe29..aafa1088 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "spectree"
-version = "1.2.4"
+version = "1.2.5"
 dynamic = []
 description = "generate OpenAPI document and validate request&response with Python annotations."
 readme = "README.md"
diff --git a/spectree/plugins/flask_plugin.py b/spectree/plugins/flask_plugin.py
index 59547652..9dee9053 100644
--- a/spectree/plugins/flask_plugin.py
+++ b/spectree/plugins/flask_plugin.py
@@ -144,12 +144,9 @@ def request_validation(self, request, query, json, form, headers, cookies):
         req_headers = dict(iter(request.headers)) or {}
         req_cookies = get_multidict_items(request.cookies) or {}
         has_data = request.method not in ("GET", "DELETE")
-        use_json = json and has_data and request.mimetype == "application/json"
-        use_form = (
-            form
-            and has_data
-            and any([x in request.mimetype for x in self.FORM_MIMETYPE])
-        )
+        # flask Request.mimetype is already normalized
+        use_json = json and has_data and request.mimetype not in self.FORM_MIMETYPE
+        use_form = form and has_data and request.mimetype in self.FORM_MIMETYPE
 
         request.context = Context(
             query.parse_obj(req_query) if query else None,


Test patch:
diff --git a/tests/flask_imports/dry_plugin_flask.py b/tests/flask_imports/dry_plugin_flask.py
index 2bb04d7f..d14697bc 100644
--- a/tests/flask_imports/dry_plugin_flask.py
+++ b/tests/flask_imports/dry_plugin_flask.py
@@ -160,6 +160,12 @@ def test_flask_validate_post_data(client, fragment):
     assert resp.status_code == 200, resp.json
     assert resp.json["score"] == sorted(resp.json["score"], reverse=False)
 
+    # POST without body
+    resp = client.post(
+        f"/api/{fragment}/flask?order=0",
+    )
+    assert resp.status_code == 422, resp.content
+
 
 def test_flask_no_response(client):
     resp = client.get("/api/no_response")