Open masons-msft opened 9 months ago
I guess, what you need is to put the api version in the @server
in TypeSpec, something like below.
@server(
"{host}.{subdomain}.{sufix}.com/{apiVersion}",
"Confidential Ledger Service",
{
@path
host?: string = "one",
@path
subdomain?: string = "two",
@path
sufix?: string = "three",
@path
apiVersion?: string = "v1"
}
)
let me know if it helps.
@qiaozha Thanks for the suggestion - unfortunately, this doesn't work well in scenarios where we have more than one API version. We still use the OpenAPI Spec as the official contract for specific versions. As @masons-msft mentioned, we are also getting the "api-version" query parameter produced in addition to the API version appearing in the path.
This seems like a discrepancy to other autorest modules to me, where the TypeSpec apiVersion parameter isn't interpreted consistently. See the linked Python issue here: https://github.com/Azure/autorest.python/issues/1778
Just want to confirm, are you saying you want use the api version twice both in the path and in the query but only want to define it once ?
No, we only want to use it once - in the path.
Maybe there's some misunderstanding here, what I am trying to suggest is, you put the apiVersion into the server decorator and then remove it from all the operation path, that has references to it. The premise is that all your operation path would be like {endpoint}/{apiVersion}/someOtherPath
, if we move it to server decorator, when you create client, the base url would become {endpoint}/apiVersion
, and the operation path would just be /someOtherPath
.
Yes, this was clear, and we tried it out - however:
It should also not be necessary to work around this. Including the API version in the path is a fairly common way of versioning an API. The use of the "api-version" query string is widely used in Azure, but is not universal. Other language emitters seem to support specifying the api version in the path, so it seems this is a missing feature / bug of the TS emitter.
Thanks for the feedback, I got your point now.
There's another issue here which is to promote the common path parameter which doesn't have to be apiVersion as I think to the client constructor, which we probably need some furthur internal discussion about this.
Hi @qiaozha , thanks for your responses on this issue!
Thanks for providing the details. I think that OpenAPI spec include api versions that are newly added may not be expected from OpenAPI spec emitter. I will confirm with TypeSpec team https://github.com/microsoft/typespec/issues/2715.
The API version being a path parameter is a reasonable ask, but am I correct in understanding we are also looking to have a single SDK package that supports multiple API versions that have had properties/operations added or removed?
From the RLC perspective this isn't something we intend to support (one RLC === one API version), and it's not clear how we would generate a DPG package that supports multiple versions in a cohesive manner.
One idea is we could provide separate subpath exports for each API version, though that would bloat the package size quite a bit and it's not entirely clear why a consumer would want to toggle between two supported API versions in a single integration?
Hi @xirzec - I think I had gotten confused when responding to an earlier comment by @qiaozha. I agree it makes sense to have a 1:1 mapping between API version and generated TypeScript library rather than having one TypeScript library that supports all API versions. The main thing would be for API version in the TypeScript client to be a fixed constant that aligns with the version of the API the TypeScript SDK is generated for. This would ensure that all API calls that are able to be made through the TypeScript client have a valid path.
That sounds good to me!
@masons-msft I want to confirm a few things,
@xirzec I wonder if we are going to promote api version for both modular and RLC if it's defined in path parameter ? Also, how are we going to handle default value if we decide to not promote it ? Which is kind of conflict with what we agreed before for default value ? https://github.com/Azure/autorest.typescript/issues/2049#issuecomment-1758794386
@qiaozha - Thanks for your questions. Here are the thoughts of me and @sjiherzig :
If I'm understanding @masons-msft correctly, it sounds like we can internally set the API version when constructing the URL for the request to be a constant that is fixed in the generated code. If the SDK is regenerated later against updated TypeSpec, this constant may be updated, but as long as what is exposed to the consumer stays consistent (modulo any breaks in the REST API itself), we are okay with it.
It doesn't sound like there is a goal here for allowing multiple API versions or having the API version be controllable by the SDK consumer, which aligns with our current design philosophy.
I think the sticking point that @qiaozha may want clarity on is since RLC uses the paths themselves as the operation identifier for the user, ideally we'd have some work in the code generator so the consumer could write something like
client.path("/exampleResources/{id}", "id-goes-here").get();
but the client would actually request {endpoint}/{api-version}/exampleResources/{id}
.
versus today where we might naively generate something like:
client.path("/2024-01-01/exampleResources/{id}", "id-goes-here").get();
Which would then be broken when the API version changed.
Put another way: we want to ensure the api-version in the path is set without being exposed explicitly to the user.
Yes, that seems right! I don't think there was any question for me there, but if there was feel free to let me know.
This is a belated question, but for my own learning, could you spell out what RLC means for me?
This is a belated question, but for my own learning, could you spell out what RLC means for me?
Here's a helpful overview of RLC: https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/rest-clients.md
Let us know if you still have any questions after perusing it! 👍
Yes, @xirzec that is the breaking I worried about. I feel like there's no elegant way to support path parameter to have default value in RLC. if we have something like
client.path("{api-version}/exampleResources/{id}", "id-goes-here").get();
and then try to pass the api-version when build the url, that would be weird right ? it's ambiguous to me where exactly "id-goes-here" should match.
@qiaozha agreed, I think we have to hide it from the public surface somehow, not sure what the best way is to prevent it from leaking out into either the endpoint url or the path map, maybe we'd have to have some special handling inside the client?
one simple option we could do for now is write a simple policy for this package that parsed the request URL and prepended the api-version to the path?
Reopen it, as we are not done yet.
Microsoft Fabric's API guidelines require the API version to be a path parameter rather than a query parameter. We would like to use this tool for generating our TypeScript SDK from our TypeSpec definition but incorporating the API version as a path parameter cannot be accomplished as cleanly as we would like, at least from what we know of the tool. There are two things we would like to be able to do.
First, we would like to set the API version as part of the client creation or route definition rather than having to specify the API version as a parameter in every request. It seems like this is already a feature in the autorest.python project.
Second, we would like
api-version
to not be automatically added as a query parameter to all requests. I believe there is already an issue that has been created related to this along with a pull request to resolve it.Are there already features to support this use case that we are simply not aware of? If not, would it be possible to add this as a feature?
Here is a quick example of what our TypeSpec looks like.
The generated
clientDefinition.ts
file would then have a Routes interface like the following.Is there a way to either set the path to
"/v1/exampleResource/{id}"
with noapiVersion
parameter or set the client'sbaseUrl
to include the api version at the end and then have all paths look like"/exampleResource/{id}"
?