Skip to content
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

Arm migration docs and template enhancements #176

Merged
merged 15 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
8 changes: 8 additions & 0 deletions .changeset/wicked-students-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@azure-tools/typespec-azure-resource-manager": patch
"@azure-tools/typespec-autorest": patch
"@azure-tools/typespec-samples": patch
"@azure-tools/typespec-azure-website": patch
---

Update references to ARM, Add template customization parameters, add migration docs
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,6 @@ packages/samples/test/output/azure/templates-contoso/setup.*
.idea/

docs/**/js-api/

# vitest temporary files
**/vitest.config.ts.timestamp*
2 changes: 1 addition & 1 deletion docs/emitters/typespec-autorest/reference/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ toc_max_heading_level: 3

### `@useRef` {#@Autorest.useRef}

`@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as ARM common types.
`@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as Azure Resource Manager common types.

`@useRef` can be specified on Models and ModelProperty.

Expand Down
228 changes: 228 additions & 0 deletions docs/howtos/migrate-swagger/migrate-arm-tips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# Migrate ARM Specs

The Swagger Converter will not be able to accurately represent every part of every API in TypeSpec. This document
outlines some common changes you might need to make to a converted TypeSpec to make it conform to your existing service API and
pass check-in validations.

## Resolving Swagger Breaking Change Violations

### Changing the Names of Request Payload Parameters

For operations with non-empty request bodies (PUT, POST, PATCH), the TypeSpec operation templates provide a default name for the
request parameter corresponding to the request payload. You can use augment decorators to make changes to this parameter, and other parts of the operation signature.

The following sections show how to do this for each operation template.

#### CreateOrUpdate (PUT) APIs

Given a PUT operation, for example:

```tsp
interface Widgets {
createOrUpdate is ArmResourceCreateOrReplaceAsync<Widget>;
}
```

The name of the request body parameter is `resource` so you can change the name in clients using an augment decorator

```tsp
@@projectedName(Widgets.createOrUpdate::parameters.resource,
markcowl marked this conversation as resolved.
Show resolved Hide resolved
"client",
"<desired-request-body-parameter-name>"
);
```

Note that this works for _any_ PUT operation template.

#### Update (PATCH) APIs

Given a PATCH operation, for example:

```tsp
interface Widgets {
update is ArmResourcePatchAsync<Widget, WidgetProperties>;
}
```

The name of the request body parameter is `properties` so you can change the name in clients using an augment decorator

```tsp
@@projectedName(Widgets.update::parameters.properties,
"client",
"<desired-request-body-parameter-name>"
);
```

Note that this works for _any_ PATCH operation template.

### Action (POST) APIs

Given a POST operation, for example:

```tsp
interface Widgets {
mungeWidget is ArmResourceActionAsync<Widget, MungeRequest, MungeResponse>;
}
```

The name of the request body parameter is `body` so you can change the name in clients using an augment decorator

```tsp
@@projectedName(Widgets.mungeWidget::parameters.body,
"client",
"<desired-request-body-parameter-name>"
);
```

Note that this works for _any_ POST operation template.

### Adding Request Query or Header Parameters

The `Parameters` template parameter allows you to specify additional parameters after the operation path (for example, query and header parameters) in the form of a model, with each model property corresponding to a parameter. You may use intersection to combine multiple separate parameters.

```tsp
// all list query params
listBySubscription is ArmListBySubscription<Widget, Parameters = Azure.Core.StandardListQueryParameters>;

// intersecting individual parameters
listBySubscription is ArmListBySubscription<Widget, Parameters = Azure.Core.TopQueryParameter & Azure.Core.SkipQueryParameter>;
```

### Changing Response Types

The `Response` parameter allows you to specify non-error responses to the operation.

```tsp
// all list query params
listBySubscription is ArmListBySubscription<Widget, Response = MyCustomCollectionType>;
```

### Changing Error Types

The `Error` parameter allows you to change the default error type used in an operation.

```tsp
// all list query params
listBySubscription is ArmListBySubscription<Widget, Error = MyCustomError>;
```

### Converting Synchronous Operations to LROs

You can generally choose an asynchronous operation template that matches your operation.

#### Templates for Async PUT Operations

- `ArmCreateOrReplaceAsync` is a PUT operation that uses the 'resource' definition in the request body, and return a `200` response and a `201` response, both of which contain the created/updated resource in the response payload. The 201 response contains 'Location` LRO header.
markcowl marked this conversation as resolved.
Show resolved Hide resolved

```tsp
createOrUpdate is ArmCreateOrReplaceAsync<Resource>;
```

- `ArmCreateOrUpdateAsync`is a PUT operation that uses the 'resource' definition in the request body, and return a `200` response and a `201` response, both of which contain the created/updated resource in the response payload. The 201 response contains 'Azure-AsyncOperation` LRO header.

```tsp
createOrUpdate is ArmCreateOrUpdateAsync<Resource>;
```

#### Templates for Async PATCH Operations

- `ArmTagsPatchAsync` is a PATCH operation that only allows changing the resource tags (the minimum for Azure Resource Manager).

```tsp
update is ArmTagsPatchAsync<Resource>;
```

- `ArmResourcePatchAsync`is a PATCH operation that uses the visibility settings to select properties for the PATCH request body(any property with no visibility setting, or including visibility "update"). It follows the required 202 pattern to resolve the LRO via location, although this can be customized using the `LroHeaders` parameter.

```tsp
update is ArmResourcePatchAsync<Resource, ResourceProperties>;
```

- `ArmCustomPatchAsync`is a PATCH operation that allows you to customize the PATCH request body.

```tsp
update is ArmCustomPatchAsync<Resource, PatchRequestBody>;
```

#### Templates for Async POST (Action) Operations

- `ArmResourceActionAsync` is a POST operation that allows you to specify the request and response body for a resource action operation. It follows the required 202 pattern to resolve the LRO via location, although this can be customized using the `LroHeaders` parameter.

```tsp
doStuff is ArmResourceActionAsync<Resource, ActionRequest, ActionResponse>;

// with no request body
doStuffNoRequest is ArmResourceActionAsync<Resource, void, ActionResponse>;

// with no response body
doStuffCommand is ArmResourceActionAsync<Resource, ActionRequest, void>;
```

#### Templates for Async DELETE Operations

- `ArmResourceDeleteWithoutOKAsync` is a DELETE operation that uses no request body, will return a `202` response in the case of an Asynchronous delete operation, and a `204` response in case the resource does not exist.

```tsp
delete is ArmResourceDeleteWithoutOKAsync<Resource>;
```

- `ArmResourceDeleteAsync`iis a DELETE operation that uses no request body, and return a `200` response in the case of a successful synchronous delete, a `202` response in the case of an Asynchronous delete operation, and a `204` response in case the resource does not exist.

```tsp
createOrUpdate is ArmResourceDeleteAsync<Resource>;
```

## Resolving Swagger LintDiff Violations

### `VisibilityChanged` for `nextLink` and `value` properties

The issue is that some older specifications marked these values as read only. This has no real impact on the API or client generation, but it is easy to mitigate for the whole specification. To fix, simply add the following augment decorator statements to the `main.tsp` file.

```tsp
@@visibility(Azure.Core.Page.value, "read");
@@visibility(Azure.Core.Page.nextLink, "read");
```

### `ProvisioningStateMustBeReadOnly`

This violation is caused by a problem with the mechanism that ARM Api validation uses to determine if a [property is read-only. You can work around the issue by setting the `use-read-only-status-schema` configuration setting in `azure/tools/typespec-autorest` options to `true` in your `tspConfig.yaml` configuration file:

```yml
emit:
- "@azure-tools/typespec-autorest"
options:
"@azure-tools/typespec-autorest":
use-read-only-status-schema: true
```

### `LroLocationHeader`

This violation occurs when your spec uses an LRO operation template that follows the older version of LRO standards. Tof fix the issue, you would change the operation template to match the latest recommendation.

#### PUT Operations

```tsp
// LRO PUT template with required headers and no 200 response
createOrUpdate is ArmResourceCreateOrReplaceAsync<MyResource>;
```

#### PATCH Operations

```tsp
// LRO PATCH template with required headers, response codes, and lro options
update is ArmResourcePatchAsync<MyResource, MyResourceProperties>;
```

### POST(Action) Operations

```tsp
// LRO POST (Action) template with required headers, response codes, and lro options
doAction is ArmResourceActionAsync<MyResource, RequestModel, ResponseModel>;
```

### DELETE Operations

```tsp
// LRO delete template with required headers and no 200 response
delete is ArmResourceDeleteWithoutOKAsync<MyResource>;
```
Loading
Loading