Skip to content

fix(python-flask, python-aiohttp): handle JSON content header/cookie params in generated tests and controllers - #25487

Open
khayashi4337 wants to merge 1 commit into
OpenAPITools:masterfrom
khayashi4337:fix/python-connexion-test-json-header-example
Open

khayashi4337 wants to merge 1 commit into
OpenAPITools:masterfrom
khayashi4337:fix/python-connexion-test-json-header-example

Conversation

@khayashi4337

@khayashi4337 khayashi4337 commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Header and cookie parameters defined with content: application/json (instead of schema) don't work end to end in python-flask / python-aiohttp. There are two problems:

  1. The generated test sends None. The generic example lookup (DefaultCodegen.setParameterExampleValue) only looks at parameter.example, parameter.examples and parameter.schema.example. A content parameter has no schema, and its example lives in the media type. The generated test therefore sends 'X-Json-Header': None. The controller's json.loads(...) fails, and the test gets a 500.
  2. The controller calls object.from_dict(...). When the media type schema is an inline object rather than a $ref model, the generated controller emits x_json_header = object.from_dict(x_json_header). That also gives a 500.

I didn't find an existing issue for this.

Changes

  • Example value. AbstractPythonConnexionServerCodegen overrides setParameterExampleValue for JSON content header/cookie parameters. It takes the example from the first media type, in this order:

    1. the media type's example;
    2. the first entry of examples ($ref resolved);
    3. the schema's example ($ref resolved);
    4. otherwise a minimal JSON value derived from the schema type.

    The value is serialized to JSON and emitted as a Python string literal through the x-python-connexion-test-header-value vendor extension. The flask, aiohttp and blueplanet test templates use it when present.

  • from_dict call. The controller calls X.from_dict(...) for a header/cookie parameter only when its type is an actual generated model, i.e. isModel and not plain object. Inline objects, free-form values, maps and primitives get the json.loads result as is. $ref models generate exactly as before.

  • Parameters defined with schema are unchanged.

Verification

  • New tests in AbstractPythonConnexionServerCodegenTest:

    • the example taken from the media type example, examples, $ref'd examples, schema example, and none;
    • the controller lines for inline and $ref content headers/cookies.

    They fail without the change. Python*Test / AbstractPython*Test pass, including forbiddenapis.

  • The generated tests were run against Connexion 2.14.2 (flask), Connexion 3.3.0 (flask, useConnexion3) and aiohttp, using specs with inline and $ref content headers. They return 200, where before they returned 500.

  • bin/generate-samples.sh bin/configs/python*.yaml: no diff.

Not covered here: query/path parameters with an inline object content schema may hit the same object.from_dict issue. This PR keeps to header/cookie parameters.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    Regenerated all bin/configs/python*.yaml samples: no diff. Generator options and docs are unchanged.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

cc @cbornet @tomplus @krjakbrjak @fa0311 (Python technical committee)

Parts of this change were drafted with AI coding assistants (Devin, Claude Code) and reviewed and verified by me.

🤖 Generated with Claude Code


Summary by cubic

Fixes JSON content header/cookie parameters (declared with content: application/json) in python-flask and python-aiohttp generated tests and controllers, which previously sent None in tests and crashed controllers with 500 errors.

  • Resolves example values from the media type example, first examples entry ($ref resolved), schema example, or a minimal JSON value derived from the schema type, and emits them as JSON string literals in generated tests.
  • Only emits Model.from_dict() conversion when the parameter type is an actual generated model class; inline objects, free-form objects, maps, and primitives pass the parsed JSON through unchanged.
  • Applies to python-flask, python-aiohttp, and python-blueplanet templates; parameters defined with schema are unchanged.

Written for commit 8b07eb2. Summary will update on new commits.

View guided diff

…params in generated tests and controllers

Header and cookie parameters declared with `content: application/json`
had two defects in the generated python-flask/python-aiohttp servers:

- The generated test sent `None` as the header value, because the generic
  example lookup never inspects parameter content media types, so
  `json.loads("None")` made requests fail with HTTP 500. A valid JSON
  string literal is now resolved for the test templates from the media
  type example, the first `examples` entry (`$ref` resolved), the media
  type schema example (`$ref` resolved), or a minimal JSON value derived
  from the schema type.
- The generated controller called `X.from_dict()` for every non-primitive
  header/cookie param, which rendered `object.from_dict()` (a class that
  does not exist) for inline `type: object` schemas and crashed at
  runtime. The conversion is now emitted only when the parameter type is
  an actual generated model class (`isModel` with a real class name), so
  inline objects, free-form objects, maps and primitives pass the
  `json.loads` result through unchanged while `$ref` model parameters
  keep their existing `Model.from_dict()` conversion.

The same vendor extension covers python-blueplanet templates.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache:31">
P2: Generated tests still omit cookie parameters: `cookieParams` is separate from `headerParams`, so this block never sends the JSON cookie value computed by the generator. Add cookie parameters to the request in both Flask and aiohttp test templates.</violation>
</file>

<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java:725">
P3: The variant list and per-generator output-path selection are copied into both new tests. Extract a helper that generates each variant once and resolves the test and controller paths, then reuse it in both tests.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

'Accept': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-produce}}{{#vendorExtensions.x-preferred-consume}}
'Content-Type': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-consume}}{{#headerParams}}
'{{baseName}}': {{{example}}},{{/headerParams}}{{#authMethods}}
'{{baseName}}': {{#vendorExtensions.x-python-connexion-test-header-value}}{{{vendorExtensions.x-python-connexion-test-header-value}}}{{/vendorExtensions.x-python-connexion-test-header-value}}{{^vendorExtensions.x-python-connexion-test-header-value}}{{{example}}}{{/vendorExtensions.x-python-connexion-test-header-value}},{{/headerParams}}{{#authMethods}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Generated tests still omit cookie parameters: cookieParams is separate from headerParams, so this block never sends the JSON cookie value computed by the generator. Add cookie parameters to the request in both Flask and aiohttp test templates.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache, line 31:

<comment>Generated tests still omit cookie parameters: `cookieParams` is separate from `headerParams`, so this block never sends the JSON cookie value computed by the generator. Add cookie parameters to the request in both Flask and aiohttp test templates.</comment>

<file context>
@@ -28,7 +28,7 @@ class {{#operations}}Test{{classname}}(BaseTestCase):
             'Accept': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-produce}}{{#vendorExtensions.x-preferred-consume}}
             'Content-Type': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-consume}}{{#headerParams}}
-            '{{baseName}}': {{{example}}},{{/headerParams}}{{#authMethods}}
+            '{{baseName}}': {{#vendorExtensions.x-python-connexion-test-header-value}}{{{vendorExtensions.x-python-connexion-test-header-value}}}{{/vendorExtensions.x-python-connexion-test-header-value}}{{^vendorExtensions.x-python-connexion-test-header-value}}{{{example}}}{{/vendorExtensions.x-python-connexion-test-header-value}},{{/headerParams}}{{#authMethods}}
             {{#isOAuth}}'Authorization': 'Bearer special-key',{{/isOAuth}}{{#isApiKey}}'{{name}}': 'special-key',{{/isApiKey}}{{#isBasicBasic}}'Authorization': 'Basic Zm9vOmJhcg==',{{/isBasicBasic}}{{#isBasicBearer}}'Authorization': 'Bearer special-key',{{/isBasicBearer}}{{/authMethods}}
         }
</file context>

}

@Test(description = "content (application/json) header/cookie params get X.from_dict() only for generated model classes; inline object schemas pass the json.loads result through")
public void testJsonContentHeaderParamsConvertOnlyGeneratedModels() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The variant list and per-generator output-path selection are copied into both new tests. Extract a helper that generates each variant once and resolves the test and controller paths, then reuse it in both tests.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java, line 725:

<comment>The variant list and per-generator output-path selection are copied into both new tests. Extract a helper that generates each variant once and resolves the test and controller paths, then reuse it in both tests.</comment>

<file context>
@@ -674,6 +674,93 @@ public void testSecuritySchemeNamesProduceValidPythonFunctions() throws IOExcept
+    }
+
+    @Test(description = "content (application/json) header/cookie params get X.from_dict() only for generated model classes; inline object schemas pass the json.loads result through")
+    public void testJsonContentHeaderParamsConvertOnlyGeneratedModels() throws IOException {
+        String specPath = "src/test/resources/3_0/python/connexion-json-header-test-values.yaml";
+
</file context>

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

1 participant