Azure / autorest.csharp

Extension for AutoRest (https://github.com/Azure/autorest) that generates C# code
MIT License
141 stars 161 forks source link

`x-ms-parameter-grouping: "postfix": "Options"` and multipart/form-data fail to generate due to missing GroupSchema support #1164

Open kant2002 opened 3 years ago

kant2002 commented 3 years ago

Experience crash in AutoRest

AutoRest code generation utility [cli version: 3.1.5; node: v15.7.0, max-memory: 4096 MB]
(C) 2018 Microsoft Corporation.
https://aka.ms/autorest
NOTE: AutoRest core version selected from configuration: ~3.1.0.
   Loading AutoRest core      'C:\Users\user\.autorest\@autorest_core@3.1.3\node_modules\@autorest\core\dist' (3.1.3)
INFORMATION: > Loading AutoRest extension '@autorest/csharp' (latest->3.0.0-beta.20210414.5)
INFORMATION: > Loading AutoRest extension '@autorest/modelerfour' (4.18.3->4.18.3)

WARNING (PreCheck/CheckDuplicateSchemas): Checking for duplicate schemas, this could take a (long) while.  Run with --verbose for more detail.
WARNING: output-folder path should be an absolute path
FATAL: Internal error in AutoRest.CSharp - Please file an issue at https://github.com/Azure/autorest.csharp/issues/new with a swagger that reproduces the issue.
Exception: The method or operation is not implemented.
   at AutoRest.CSharp.Output.Models.RestClientBuilder.BuildRequestBody(IList1 requestParameters, Dictionary2 allParameters, KnownMediaType mediaType) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Output\Models\RestClientBuilder.cs:line 338
   at AutoRest.CSharp.Output.Models.RestClientBuilder.BuildRequest(HttpRequest httpRequest, IList1 requestParameters, Dictionary2 allParameters) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Output\Models\RestClientBuilder.cs:line 138
   at AutoRest.CSharp.Output.Models.RestClientBuilder.BuildMethod(Operation operation, HttpRequest httpRequest, IEnumerable`1 requestParameters, DataPlaneResponseHeaderGroupType responseHeaderModel, String accessibility) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Output\Models\RestClientBuilder.cs:line 79
   at AutoRest.CSharp.Output.Models.DataPlaneRestClient.EnsureNormalMethods() in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\DataPlane\Output\DataPlaneRestClient.cs:line 50
   at AutoRest.CSharp.Utilities.CachedDictionary`2.EnsureValues() in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Utilities\CachedDictionary.cs:line 32
   at AutoRest.CSharp.Utilities.CachedDictionary`2.get_Item(K key) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Utilities\CachedDictionary.cs:line 48
   at AutoRest.CSharp.Output.Models.DataPlaneRestClient.GetOperationMethod(ServiceRequest request) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\DataPlane\Output\DataPlaneRestClient.cs:line 98
   at AutoRest.CSharp.Output.Models.RestClient.BuildAllMethods()+MoveNext() in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Output\Models\RestClient.cs:line 55
   at System.Collections.Generic.LargeArrayBuilder1.AddRange(IEnumerable1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at AutoRest.CSharp.Output.Models.RestClient.get_Methods() in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Output\Models\RestClient.cs:line 43
   at AutoRest.CSharp.Generation.Writers.RestClientWriter.WriteClient(CodeWriter writer, RestClient restClient) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\Generation\Writers\RestClientWriter.cs:line 33
   at AutoRest.CSharp.AutoRest.Plugins.DataPlaneTarget.Execute(GeneratedCodeWorkspace project, CodeModel codeModel, SourceInputModel sourceInputModel, Configuration configuration) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\DataPlane\AutoRest\DataPlaneTarget.cs:line 41
   at AutoRest.CSharp.AutoRest.Plugins.CSharpGen.ExecuteAsync(Task`1 codeModelTask, Configuration configuration) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\AutoRest\Plugins\CSharpGen.cs:line 54
   at AutoRest.CSharp.AutoRest.Plugins.CSharpGen.Execute(IPluginCommunication autoRest) in D:\a\1\s\autorest.csharp\src\AutoRest.CSharp\Common\AutoRest\Plugins\CSharpGen.cs:line 93

Yaml file

input-file: ../Api/obj/Api.json
directive:
- from: openapi-document
  where: $.components.schemas.*.additionalProperties
  transform: |
    return typeof $ === "boolean"
      ? ($ ? { type: "object" } : undefined)
      : $
  reason: polyfill
- from: openapi-document
  where: $.paths.*.get.parameters[?(@.schema.type === "array")]
  transform: |    
    if ($.style === undefined) {
        $.style = "form";
        $.explode = true;
    }
  reason: polyfill
- from: openapi-document
  where: $.paths.*.post.requestBody.content["multipart/form-data"].schema.properties[?(@.format === "binary")]
  transform: |    
    $.type = "file";
  reason: polyfill
csharp:
  output-folder: Generated
  namespace: Api.Client
  add-credentials: true

Swagger.json attached.

{
  "openapi": "3.0.1",
  "info": {
    "title": "API",
    "description": "API",
    "version": "v1.0"
  },
  "paths": {
    "/api/requests/custom-files": {
      "get": {
        "tags": [
          "Requests"
        ],
        "operationId": "GetCustomFilesRequests",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProcessingRequest"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProcessingRequest"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProcessingRequest"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Requests"
        ],
        "operationId": "LaunchFileTask",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "DataFile",
                  "DateColumn",
                  "PredictionColumn"
                ],
                "type": "object",
                "properties": {
                  "DataWindow": {
                    "type": "integer",
                    "format": "int32",
                    "nullable": true
                  },
                  "PredictionWindow": {
                    "type": "integer",
                    "format": "int32",
                    "nullable": true
                  },
                  "DateColumn": {
                    "type": "string"
                  },
                  "PredictionColumn": {
                    "type": "string"
                  },
                  "DataFile": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "DataWindow": {
                  "style": "form"
                },
                "PredictionWindow": {
                  "style": "form"
                },
                "DateColumn": {
                  "style": "form"
                },
                "PredictionColumn": {
                  "style": "form"
                },
                "DataFile": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ProcessingTaskStatus": {
        "enum": [
          "Started",
          "Completed",
          "Failed"
        ],
        "type": "string"
      },
      "ProcessingRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "taskId": {
            "type": "string",
            "nullable": true
          },
          "requesterUserId": {
            "type": "integer",
            "format": "int32"
          },
          "launchDate": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "$ref": "#/components/schemas/ProcessingTaskStatus"
          }
        },
        "additionalProperties": false
      }
    }
  }
}

sample.txt

MarcStoecker commented 3 years ago

Did you ever happen to find out more about it, @kant2002? Hitting the same issue here, it seems.

kant2002 commented 3 years ago

@MarcStoecker I suspect this is due to fact that multiple content type specified in GET.

MarcStoecker commented 3 years ago

Thanks for the hint! Looks like you are right. I tried to step through and patch it but it seems to involve a fair bit more that just a few tweaks. 😞

MarcStoecker commented 3 years ago

Okay, upon further investigation I am very certain, that [FromBody] and expecially [FromForm] cause this. Doesn't matter if using built-in or custom bindings.

fredrik-hellmangroup commented 3 years ago

Can confirm that [FromForm] causes this, I just stumbled across this too

chamons commented 3 years ago

We don't support GroupSchema in https://github.com/Azure/autorest.csharp/blob/feature/v3/src/AutoRest.CSharp/Common/Generation/Types/TypeFactory.cs#L43.

chamons commented 3 years ago

Here is a minimum swagger repo case: https://gist.github.com/chamons/6937d8370a47340680565e0e362d7231

If you remove:

              "x-ms-parameter-grouping": {
                "postfix": "Options"
              }

then I don't crash here (it gets angry from my hacking and slashing the response type to get a small sample).

And on the original is down to this: https://gist.github.com/chamons/56487bf0c7d0aa7c96927d377976f644