autorest
autorest copied to clipboard
A question related to modelAsString in x-ms-enum
Before asking the question:
- [x] have you checked the faq, the documentation in the docs folder and couldn't find the information there
- [x] have you checked existing issues for a similar question?
I am using autorest/[email protected]. And I need to use it with following switch on. As a result, modelerfour will create SealedChoiceSchema for x-ms-enum. The issue I ran into is that modelAsString is dropped. Is there any way I could know whether modelAsString is set to true or false in modelerfour? Would it be possible to add the modelASstring in the extensions of a SealedChoiceSchema?
always-seal-x-ms-enums: true
it is dropped because you ask for that no? Why do you want that flag then?
it is dropped because you ask for that no? Why do you want that flag then?
@timotheeguerin Thanks a lot for your quick response.
Correction. It should be autorest/[email protected] instead of autorest/[email protected].
I need the modelAsString to know whether it should be modeled as string or enum according to https://github.com/stankovski/AutoRest/blob/master/Documentation/swagger-extensions.md#x-ms-enum. Not sure why modelerfour drop modelAsString when convert swagger to modelerfour.
As we can see as below modelAsString is set and kept in the openapi-document.
But it is dropped when converted to modelerfour.
Below is the swagger I use to test x-ms-enum.
{
"swagger": "2.0",
"info": {
"title": "DatabricksClient",
"version": "2018-04-01",
"description": "ARM Databricks"
},
"host": "management.azure.com",
"schemes": ["https"],
"consumes": ["application/json"],
"produces": ["application/json"],
"security": [
{
"azure_auth": ["user_impersonation"]
}
],
"securityDefinitions": {
"azure_auth": {
"type": "oauth2",
"authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize",
"flow": "implicit",
"description": "Azure Active Directory OAuth2 Flow",
"scopes": {
"user_impersonation": "impersonate your user account"
}
}
},
"paths": {
"/providers/Microsoft.Databricks/operations/{name}": {
"get": {
"tags": ["Operation"],
"description": "Get the available RP operation.",
"operationId": "Operation_get",
"parameters": [
{
"name": "parameters",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/operation"
},
"description": "Parameters supplied to the create or update a workspace."
},
{
"$ref": "#/parameters/name"
},
{
"$ref": "#/parameters/ApiVersionParameter"
}
],
"responses": {
"200": {
"description": "OK. The request has succeeded.",
"schema": {
"$ref": "#/definitions/operation"
}
}
}
}
}
},
"definitions": {
"operation": {
"properties": {
"typeSealedChoiceAsString": {
"type": "string",
"description": "This is typeSealedChoiceAsString",
"enum": ["sealedchoice3", "sealedchoice4"],
"x-ms-enum": {
"name": "typeSealedChoiceAsString",
"modelAsString": true
}
},
"typeChoice": {
"type": "string",
"description": "This is choice",
"enum": ["choice1", "choice2"]
},
"typeSealedChoice": {
"type": "string",
"description": "This is sealed choice",
"enum": ["sealedchoice1", "sealedchoice2"],
"x-ms-enum": {
"name": "typeSealedChoice",
"modelAsString": false
}
}
},
"description": "Information about workspace."
}
},
"parameters": {
"ApiVersionParameter": {
"name": "api-version",
"in": "query",
"required": true,
"type": "string",
"description": "The API version to use for this operation."
},
"name": {
"name": "name",
"in": "path",
"required": true,
"type": "string",
"description": "The name of the operation."
}
}
}
Yeah modelerfour either makes a sealed choice(enum) or a choice(extensible enum) schema depending on modelAsString you don’t need to know the content of that value
@timotheeguerin Actually, there are three cases as I list in the swagger above.
- enum without x-ms-enum
- enum with x-ms-enum and modelAsString is true
- enum with x-ms-enum and modelAsString is false
If I set always-seal-x-ms-enums: true
, case#2 and case#3 will be generated as sealedchoice. I will have no way to know whether it should be modeled as string or enum without modelAsString.
But if I set always-seal-x-ms-enums: false
, case#1 and case#2 will be generated as choice. I will have no way to tell case#1 from case#2.
Would it be possible that you could add an extensions as below for sealed choice and choice to keep the modelAsString considering it will not be a breaking change.
extensions:
x-ms-enum:
modelAsString: true
Case 1 and 2 are the same result: extensible enum
Case 1 and 2 are the same result: extensible enum
Hi @timotheeguerin, I know current design of modelerfour after you explanation. But these two cases are handled differently in autorest.powershell. Ideally, converting swagger to modelerfour should not lose any information.
I have a look at the modelerfour code, and find extensions are set (not dropped) for both ChoiceSchema and SealedChoiceSchema. So it looks like a bug actually.
https://github.com/Azure/autorest/blob/cb3c65372ce4ce3158c51a68fc690fe02e8eb8f7/packages/extensions/modelerfour/src/modeler/modelerfour.ts#L773-L774 https://github.com/Azure/autorest/blob/cb3c65372ce4ce3158c51a68fc690fe02e8eb8f7/packages/extensions/modelerfour/src/modeler/modelerfour.ts#L789-L790
It is not a bug, known extension that are handled by modelerfour are removed because you shouldn’t have to care about them because m4 is the one ha doing the logic.
why is PowerShell the only generator that doesn’t respect this behavior
It is not a bug, known extension that are handled by modelerfour are removed because you shouldn’t have to care about them because m4 is the one ha doing the logic.
why is PowerShell the only generator that doesn’t respect this behavior
@timotheeguerin, thanks for your clarification.
Well, I understand that modelerfour is trying to handling all extensions for different language generators and hide/drop them after that. For my case, it is a legacy design of autorest.powershell based on remodeler(v3) before modelerfour actually. And that's why modelerfour design the switch always-seal-x-ms-enums: true
for those generators(actually only PowerShell) that depends on remodeler to do the migration from remodeler to modelerfour. But there is a limitation of this switch. As I mentioned above, I have no way to know whether modelAsString is set or not for an enum when this switch is turned on. My situation is that I can not turn off this switch since it will break current logic in autorest.powershell, but with the switch on I do not know whether modelAsString is set for an enum. So the only solution I can think of is modelerfour can keep the extensions or add an additional optional property called modelAsString in Sealedchoice Schema when the always-seal-x-ms-enums: true
is set. What do you think?
If PowerShell is the only generator and this is to support some legacy behavior why not use a directive to get the information you want.
exposing that property now brings confusion to all the other generators. Not excluding x-ms-enum gets similar result though not as bad.
If PowerShell is the only generator and this is to support some legacy behavior why not use a directive to get the information you want.
I am interested in this solution. Would you share more details or an example about how to do that? Guess what you said is like modelerfour will drop x-ms-enum but if I clone an x-ms-enum and rename it to something else through directive. Modelerfour will keep it.
directive:
- from: swagger-document
where: $..[?(@['x-ms-enum'])]
transform: $['x-ms-model-as-string'] = $['x-ms-enum'].modelAsString
@dolauli yeah that looks like what I would be doing. Does this not work?
@dolauli yeah that looks like what I would be doing. Does this not work?
It works. Thank a bunch for your suggestion
@dolauli yeah that looks like what I would be doing. Does this not work?
It works. Thank a bunch for your suggestion
@timotheeguerin Disappointed to find the solution does not work in some cases. Below is a case that the solution does not work.
The swagger is as following, which is located in here.
{
"name": "$expand",
"in": "query",
"required": false,
"type": "string",
"enum": [
"kerb"
],
"x-ms-enum": {
"name": "ListKeyExpand"
},
"description": "Specifies type of the key to be listed. Possible value is kerb."
}
Accordingly the directive I add will change it to below by adding "x-ms-model-as-string": false
.
{
"name": "$expand",
"in": "query",
"required": false,
"type": "string",
"enum": [
"kerb"
],
"x-ms-enum": {
"name": "ListKeyExpand"
},
"description": "Specifies type of the key to be listed. Possible value is kerb.",
"x-ms-model-as-string": false
}
But after my directive take effective, some plugin will change it to below later by moving enum definition to schema.
{
"name": "$expand",
"in": "query",
"description": "Specifies type of the key to be listed. Possible value is kerb.",
"required": false,
"x-ms-model-as-string": false,
"schema": {
"enum": [
"kerb"
],
"x-ms-enum": {
"name": "ListKeyExpand"
},
"type": "string"
}
}
Since x-ms-model-as-string is not moved into the schema, I will not see it in the sealed choice in the model.
Is it possible you could keep the x-ms-enum instead of dropping it if always-seal-x-ms-enums: true
? I believe the change will have no impact on other generators since only autorest.powershell set always-seal-x-ms-enums: true
.
@dolauli can you confirm this is working https://github.com/Azure/autorest/pull/4692#issuecomment-1349059739?
Another question is why is this just surfacing now?
Actually this is now causing some issue with flattening models. As x-ms-enum
get included in the flattened type and this cause all kind of issues so most likely not going to be adding that.
The other alternative is to change the value inside of x-ms-enum
with the directive, no? Always update the default to be what you want and then you can depend on it being a Choice or a SealedChoice
@dolauli can you confirm this is working #4692 (comment)?
Another question is why is this just surfacing now?
Ye, it works. To your question, previously we just treat modelAsString true or false the same.
Actually this is now causing some issue with flattening models. As
x-ms-enum
get included in the flattened type and this cause all kind of issues so most likely not going to be adding that.
Not sure what the issue is. Guess what you said is if you keep 'x-ms-enum', it will cause other issues. Will rename it to something else like 'x-ms-enum-processed' instead of removing it will workaround these issues?
The other alternative is to change the value inside of
x-ms-enum
with the directive, no? Always update the default to be what you want and then you can depend on it being a Choice or a SealedChoice
I do not quite get your point here. Would you give more details? BTW, I am seeking is not to change some configs in x-ms-enum but to keep them so that I could handle them in autorest.powershell.
So given an enum what do you want?
- enum with no x-ms-enum:
- enum with x-ms-enum.modelAsString=true
- enum with x-ms-enum.modelAsString=false
What do you expect for each of one those cases?
I set the config always-seal-x-ms-enums: true
.
So case 1 will be generated as Choice. And I just handle them as the normal type (string, number, etc.) instead of enum.
Case 2 and Case 3 will be generated as Sealed Choice. Currently, I do not case whether modelAsString is set. And will generate a C# class for it.
What I want to do now is to add support for modelAsString, and generate an enum for it if modelAsString is set to false.
So you want 3 different output?
- primitive type
- Some class
- Enum
And the issue doesn't seem to be particularly related to x-ms-enum
there seems to be something more broken about keeping extensions there. I don't really have time to investigate that right now with cadl. Feel free to dig into it.
So you want 3 different output?
- primitive type
- Some class
- Enum
Yes.
@timotheeguerin, Understood. Actually, I figured out a workaround for the failed case I mentioned above. Let's keep the question open for a while in case I find any other failed case.