Skip to content

Add legacy operations for multi-path scenario #2095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .chronus/changes/legacyOperations-2025-0-17-19-14-32.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@azure-tools/typespec-azure-resource-manager"
---

Add legacy operations for multi-path scenario
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
import "./managed-identity.tsp";
import "./decorator.tsp";
import "./operations.tsp";
275 changes: 275 additions & 0 deletions packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
import "@typespec/http";
import "@typespec/rest";
import "@typespec/versioning";
import "@azure-tools/typespec-azure-core";
import "@azure-tools/typespec-azure-resource-manager";

using TypeSpec.Http;
using TypeSpec.Rest;
using TypeSpec.Versioning;
using Azure.Core;
using Azure.ResourceManager;

namespace Azure.ResourceManager.Legacy {
interface LegacyOperations<
ParentParameters extends {},
ResourceTypeParameter extends {},
ErrorType extends {} = ErrorResponse
> {
/**
* @dev A long-running resource CreateOrUpdate (PUT)
* @template Resource the resource being created or updated
* @template LroHeaders Optional. Allows overriding the lro headers returned on resource create
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response(s) for the PUT operation
*/
#suppress "@azure-tools/typespec-azure-core/no-private-usage"
@autoRoute
@doc("Create a {name}", Resource)
@armResourceCreateOrUpdate(Resource)
@Azure.Core.Foundations.Private.defaultFinalStateVia(#["location", "azure-async-operation"])
@put
CreateOrUpdateAsync<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader<FinalResult = Resource> &
Azure.Core.Foundations.RetryAfterHeader,
Parameters extends {} = {},
Response extends {} = ArmResourceUpdatedResponse<Resource> | ArmResourceCreatedResponse<
Resource,
LroHeaders
>
>(
...ParentParameters,
...ResourceTypeParameter,
...Parameters,
@doc("Resource create parameters.") @bodyRoot resource: Resource,
): Response | ErrorType;

/**
* @dev A synchronous resource CreateOrUpdate (PUT)
* @template Resource the resource being created or updated
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response(s) for the PUT operation
*/
#suppress "@azure-tools/typespec-azure-core/no-private-usage"
@autoRoute
@doc("Create a {name}", Resource)
@armResourceCreateOrUpdate(Resource)
@put
CreateOrUpdateSync<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
Parameters extends {} = {},
Response extends {} = ArmResourceUpdatedResponse<Resource> | ArmResourceCreatedSyncResponse<Resource>
>(
...ParentParameters,
...ResourceTypeParameter,
...Parameters,
@doc("Resource create parameters.") @bodyRoot resource: Resource,
): Response | ErrorType;

/**
* @dev A long-running resource Update (PATCH)
* @template Resource the resource being created or updated
* @template PatchModel the PATCH request model
* @template LroHeaders Optional. Allows overriding the lro headers returned on resource create
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response(s) for the PATCH operation
*/
@autoRoute
@doc("Update a {name}", Resource)
@armResourceUpdate(Resource)
@patch
CustomPatchAsync<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
PatchModel extends {} = Azure.ResourceManager.Foundations.TagsUpdateModel<Resource>,
LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader<
Azure.Core.StatusMonitorPollingOptions<ArmOperationStatus>,
Resource,
string
> &
Azure.Core.Foundations.RetryAfterHeader,
Parameters extends {} = {},
Response extends {} = ArmResponse<Resource> | ArmAcceptedLroResponse<
"Resource update request accepted.",
LroHeaders
>
>(
...ParentParameters,
...ResourceTypeParameter,
...Parameters,
@doc("The resource properties to be updated.") @bodyRoot properties: PatchModel,
): Response | ErrorType;

/**
* @dev A synchronous resource Update (PATCH)
* @template Resource the resource being created or updated
* @template PatchModel the PATCH request model
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response(s) for the PATCH operation
*/
@autoRoute
@doc("Update a {name}", Resource)
@armResourceUpdate(Resource)
@patch
CustomPatchSync<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
PatchModel extends {} = Azure.ResourceManager.Foundations.TagsUpdateModel<Resource>,
Parameters extends {} = {},
Response extends {} = ArmResponse<Resource>
>(
...ParentParameters,
...ResourceTypeParameter,
...Parameters,
@doc("The resource properties to be updated.") @bodyRoot properties: PatchModel,
): Response | ErrorType;

/**
* @dev Delete a resource asynchronously
Copy link
Member

Choose a reason for hiding this comment

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

I'd like us to be explicit that these APIs are subject to change, and should only be used in converting legacy APIs to typespec.

If we could, I would consider an experimental types export like this: https://github.com/microsoft/typespec/blob/main/packages/events/package.json#L28

But we would have to validate that this works with imports and standard tsp compilation. The best current solution might be docs and either a decorator or rule that marks these types as volatile, and issues a warning if you use them (perhaps through conbining a decorator and linting rule, so that it could be globally suppressed in config).

* @template Resource The resource being deleted
* @template LroHeaders The lro headers for the operation
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response(s) for the delete operation
*/
#suppress "@azure-tools/typespec-azure-core/no-response-body" "Valid"
@autoRoute
@doc("Delete a {name}", Resource)
@delete
@deletesResource(Resource)
@armResourceDelete(Resource)
DeleteWithoutOkAsync<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader &
Azure.Core.Foundations.RetryAfterHeader,
Parameters extends {} = {},
Response extends {} = ArmDeletedResponse | ArmDeleteAcceptedLroResponse<LroHeaders> | ArmDeletedNoContentResponse
>(...ParentParameters, ...ResourceTypeParameter, ...Parameters): Response | ErrorType;

/**
* @dev Delete a resource synchronously
* @template Resource The resource being deleted
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response(s) for the delete operation
*/
#suppress "@azure-tools/typespec-azure-core/no-response-body" "Valid"
@autoRoute
@doc("Delete a {name}", Resource)
@delete
@deletesResource(Resource)
@armResourceDelete(Resource)
DeleteSync<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
Parameters extends {} = {},
Response extends {} = ArmDeletedResponse | ArmDeletedNoContentResponse
>(...ParentParameters, ...ResourceTypeParameter, ...Parameters): Response | ErrorType;

/**
* @dev Get a resource
* @template Resource The resource being read
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The success response for a get operation.
*/
@autoRoute
@doc("Get a {name}", Resource)
@get
@readsResource(Resource)
@armResourceRead(Resource)
Read<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
Parameters extends {} = {},
Response extends {} = ArmResponse<Resource>
>(...ParentParameters, ...ResourceTypeParameter, ...Parameters): Response | ErrorType;

/**
* @dev List a resource
* @template Resource The resource being listed
* @template Parameters Optional. Additional parameters after the path parameters
* @template Response Optional. The response returned by the list
*/
@autoRoute
@doc("List {name} resources", Resource)
@get
@listsResource(Resource)
@segmentOf(Resource)
@armResourceList(Resource)
List<
Resource extends Azure.ResourceManager.CommonTypes.Resource,
Parameters extends {} = {},
Response extends {} = ArmResponse<ResourceListResult<Resource>>
>(...ParentParameters, ...Parameters): Response | ErrorType;

/**
* A synchronous resource action.
* @template Resource The resource being acted upon
* @template Request The request model for the action
* @template Response The response model for the action
* @template Parameters Optional. Additional parameters after the path parameters
*/
#suppress "@azure-tools/typespec-azure-core/no-private-usage"
@autoRoute
@armResourceAction(Resource)
@Private.enforceConstraint(Resource, Foundations.Resource)
@post
@returnsDoc("Azure operation completed successfully.")
ActionSync<
Resource extends Foundations.Resource,
Request extends TypeSpec.Reflection.Model | void,
Response extends TypeSpec.Reflection.Model | void,
Parameters extends {} = {}
>(
...ParentParameters,
...ResourceTypeParameter,
...Parameters,

@doc("The content of the action request")
@bodyRoot
body: Request,
Copy link
Member

Choose a reason for hiding this comment

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

I think we want to add two add an additional parameter for every one of these operations that has a request body, like:

RequestBody extends {} = {
  @doc("The content of the action request")
      @bodyRoot
      body: Request
},

This would allow optional request bodies, which are not standard, but occur in legacy apis

Copy link
Member

Choose a reason for hiding this comment

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

It also allows renaming the body parameter without decorators.

): Response | ErrorType;

/**
* A long-running resource action.
* @template Resource The resource being acted upon
* @template Request The request model for the action
* @template LroHeaders Optional. Allows overriding the headers returned in the Accepted response
* @template Response The response model for the action
* @template Parameters Optional. Additional parameters after the path parameters
*/
#suppress "@azure-tools/typespec-azure-core/no-response-body" "ARM"
#suppress "@azure-tools/typespec-azure-core/no-private-usage" "template"
@autoRoute
@armResourceAction(Resource)
@Private.enforceConstraint(Resource, Foundations.Resource)
@post
@returnsDoc("Azure operation completed successfully.")
ActionAsync<
Resource extends Foundations.Resource,
Request extends TypeSpec.Reflection.Model | void,
Result extends TypeSpec.Reflection.Model | void,
LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader<
Azure.Core.StatusMonitorPollingOptions<ArmOperationStatus>,
Result,
string
> &
Azure.Core.Foundations.RetryAfterHeader,
Parameters extends {} = {},
Response extends {} | void = ArmAcceptedLroResponse<
"Resource operation accepted.",
LroHeaders
> | Result
>(
...ParentParameters,
...ResourceTypeParameter,
...Parameters,

@doc("The content of the action request")
@bodyRoot
body: Request,
): Response | ErrorType;
}
/**
* @dev Get the provider namespace key-value pair
* @template Resource Optional. The resource to get the provider namespace for.
*/
model Provider<Resource extends {} = TenantActionScope> {
...ProviderNamespace<Resource>;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2688,6 +2688,24 @@ model Foo is TrackedResource<FooProperties> {
| --------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| identity? | [`ManagedServiceIdentityV4`](./data-types.md#Azure.ResourceManager.Legacy.ManagedServiceIdentityV4) | The managed service identities assigned to this resource. |

### `Provider` {#Azure.ResourceManager.Legacy.Provider}

```typespec
model Azure.ResourceManager.Legacy.Provider<Resource>
```

#### Template Parameters

| Name | Description |
| -------- | --------------------------------------------------------- |
| Resource | Optional. The resource to get the provider namespace for. |

#### Properties

| Name | Type | Description |
| -------- | -------------------------------- | ----------- |
| provider | `"Microsoft.ThisWillBeReplaced"` | |

### `ManagedServiceIdentityType` {#Azure.ResourceManager.Legacy.ManagedServiceIdentityType}

Type of managed service identity (where both SystemAssigned and UserAssigned types are allowed).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,12 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager

- [`@customAzureResource`](./decorators.md#@Azure.ResourceManager.Legacy.customAzureResource)

### Interfaces

- [`LegacyOperations`](./interfaces.md#Azure.ResourceManager.Legacy.LegacyOperations)

### Models

- [`ManagedServiceIdentityV4`](./data-types.md#Azure.ResourceManager.Legacy.ManagedServiceIdentityV4)
- [`ManagedServiceIdentityV4Property`](./data-types.md#Azure.ResourceManager.Legacy.ManagedServiceIdentityV4Property)
- [`Provider`](./data-types.md#Azure.ResourceManager.Legacy.Provider)
Loading
Loading