microsoft / kiota

OpenAPI based HTTP Client code generator
https://aka.ms/kiota/docs
MIT License
2.83k stars 194 forks source link

Models not generating for requests with multiple content types #4734

Closed mspearey closed 3 months ago

mspearey commented 3 months ago

What are you generating using Kiota, clients or plugins?

API Client/SDK

In what context or format are you using Kiota?

Nuget tool

Client library/SDK language

Csharp

Describe the bug

I am trying to generate a CSharp api client from an openapi document with kiota 1.14.0 but model files are not being generated when the requestBody content type does not match application/json, or if application/json exists along side multipart/form-data.

Based on the document, JWTObtainPairRequest should have a Model generated, but this is only true when the endpoint request content mime type is only application/json

Expected behavior

Model files should be generated regardless of mime types.

Based on the example, the models folder should have the type JWTObtainPairRequest

How to reproduce

kiota generate -l CSharp -c MyApiClient -n My.ApiClient -d ./test.yaml -o ./MyApiClient --include-path "**/token/**" --co --cc

Open API description file

`openapi: 3.0.3 info: title: API version: 2.0 paths: /api/v2/token/new/: post: operationId: Obtain new access/refresh token pair description: Obtain JWT pair tags:

`

Kiota Version

1.14.0

Latest Kiota version known to work for scenario above?(Not required)

No response

Known Workarounds

Reduce request mime content types to just application/json

Configuration

Debug output

Click to expand log ``` > kiota generate -l CSharp -c MyApiClient -n My.Client -d ./test.yaml -o ./MyApiClient --include-path "**/token/**" --co --cc --ll debug info: Kiota.Builder.KiotaBuilder[0] Cleaning output directory C:\Project\.\ClientTest dbug: Kiota.Builder.KiotaBuilder[0] kiota version 1.14.0 info: Kiota.Builder.KiotaBuilder[0] loaded description from local source dbug: Kiota.Builder.KiotaBuilder[0] step 1 - reading the stream - took 00:00:00.0187292 dbug: Kiota.Builder.KiotaBuilder[0] step 2 - parsing the document - took 00:00:00.2263048 dbug: Kiota.Builder.KiotaBuilder[0] step 3 - updating generation configuration from kiota extension - took 00:00:00.0001934 dbug: Kiota.Builder.KiotaBuilder[0] step 4 - filtering API paths with patterns - took 00:00:00.0348416 dbug: Kiota.Builder.KiotaBuilder[0] step 5 - checking whether the output should be updated - took 00:00:00.0281600 dbug: Kiota.Builder.KiotaBuilder[0] step 6 - create uri space - took 00:00:00.0048704 dbug: Kiota.Builder.KiotaBuilder[0] InitializeInheritanceIndex 00:00:00.0072927 dbug: Kiota.Builder.KiotaBuilder[0] CreateRequestBuilderClass 00:00:00 dbug: Kiota.Builder.KiotaBuilder[0] MapTypeDefinitions 00:00:00.0181795 dbug: Kiota.Builder.KiotaBuilder[0] TrimInheritedModels 00:00:00 dbug: Kiota.Builder.KiotaBuilder[0] CleanUpInternalState 00:00:00 dbug: Kiota.Builder.KiotaBuilder[0] step 7 - create source model - took 00:00:00.2189239 dbug: Kiota.Builder.KiotaBuilder[0] 77ms: Language refinement applied dbug: Kiota.Builder.KiotaBuilder[0] step 8 - refine by language - took 00:00:00.0798026 dbug: Kiota.Builder.KiotaBuilder[0] step 9 - writing files - took 00:00:00.0837791 info: Kiota.Builder.KiotaBuilder[0] loaded description from local source dbug: Kiota.Builder.KiotaBuilder[0] step 10 - writing lock file - took 00:00:00.0277753 Generation completed successfully dbug: Kiota.Builder.KiotaBuilder[0] Api manifest path: C:\Project\apimanifest.json Hint: use the info command to get the list of dependencies you need to add to your project. Example: kiota info -d "C:\Project\.\test.yaml" -l CSharp ```

Other information

No response

mspearey commented 3 months ago

Screenshot showing the output of the created client. JWTObtainPairRequest model is missing.

image

mspearey commented 3 months ago

So even with --structured-mime-types "application/json" the issue still persists.

From what I can see the check that happens here https://github.com/microsoft/kiota/blob/main/src/Kiota.Builder/KiotaBuilder.cs#L1476 The call to IsMultipartFormDataSchema (https://github.com/microsoft/kiota/blob/main/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs#L45) returns true because the multipart/form-data exists as part of the schema.

Would it be valid to add a check in IsMultipartFormDataSchema, that checks for "multipart/form-data" in structuredMimeTypes? Although this would still cause the issue with the default structuredMimeTypes value

return structuredMimeTypes.Contains(multipartMimeTypes.First()) && source.GetValidSchemas(structuredMimeTypes).FirstOrDefault() is OpenApiSchema schema && source.GetValidSchemas(multipartMimeTypes).FirstOrDefault() == schema;

andrueastman commented 3 months ago

Thanks for raising this @mspearey

Any chance you can re-share the input openApi document? I belive the issue may be around the passing of the configuration --structured-mime-types "application/json really as IsMultipartFormDataSchema would return false if multipart/form-data is not present in the input configuration which is passed as the second parameter at

https://github.com/microsoft/kiota/blob/main/src/Kiota.Builder/KiotaBuilder.cs#L1476

mspearey commented 3 months ago

Sure, here is the document openapi.json

I managed to step through the project in debug mode. So can possibly provide more insight.

I get the same result with or without using --structured-mime-types. The default value of structuredMimeTypes is "application/json;q=1", "text/plain;q=0.9", "application/x-www-form-urlencoded;q=0.2", "multipart/form-data;q=0.1",

multipartMimeTypes = new(new string[] { "multipart/form-data" });

The IsMultipartFormDataSchema is currently this return source.GetValidSchemas(structuredMimeTypes).FirstOrDefault() is OpenApiSchema schema && source.GetValidSchemas(multipartMimeTypes).FirstOrDefault() == schema;

With either passing the argument with "application/json" or not the first element in structuredMimeTypes is set to "application/json". The source variable has a list of the types from the schema, in this case it will be "application/json", "application/x-www-form-urlencoded", and "multipart/form-data". So the first part of that statement returns true, and the second statement also returns true as the schema has the multipart mime type.

I've believe I have narrowed the issue down though. There are a few assumptions being made.

  1. The IsMultipartFormDataSchema call assumes it will be the only content type.
  2. That when Multipart is used, that the encoding field will be present, the openapi documentation doesn't state the field is required.

I have addressed these in a PR #4747 .

  1. Have added an additional method that checks for the multipart content type, if it's the only content type, and then finally if it is the top priority type.
  2. If the type is identified as multipart, I have added a check for encoding property, if not present it follows the non multipart model declaration