Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 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
136 changes: 136 additions & 0 deletions docs/experimental-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Experimental APIs

The Microsoft.OpenApi library includes a set of experimental APIs that are available for evaluation.
These APIs are subject to change or removal in future versions without following the usual deprecation process.

Using an experimental API will produce a compiler diagnostic that must be explicitly suppressed
to acknowledge the experimental nature of the API.

## Suppressing Experimental API Diagnostics

To use an experimental API, suppress the corresponding diagnostic in your project:

### Per call site

```csharp
#pragma warning disable OAI020
var v2Path = OpenApiPathHelper.GetVersionedPath(path, OpenApiSpecVersion.OpenApi2_0);
#pragma warning restore OAI020
```

### Per project (in `.csproj`)

```xml
<PropertyGroup>
<NoWarn>$(NoWarn);OAI020</NoWarn>
</PropertyGroup>
```

---

## OAI020 — Path Version Conversion

| Diagnostic ID | Applies to | Since |
|---|---|---|
| `OAI020` | `OpenApiPathHelper`, `OpenApiValidatorError.GetVersionedPointer` | v3.6.0 |

### Overview

The path version conversion APIs translate JSON Pointer paths produced by the `OpenApiWalker`
(which always uses the v3 document model) into their equivalents for a specified OpenAPI
specification version.

This is useful when validation errors or walker paths need to be reported relative to
the original document version (e.g., Swagger v2) rather than the internal v3 representation.

### APIs

#### `OpenApiPathHelper.GetVersionedPath(string path, OpenApiSpecVersion targetVersion)`

Converts a v3-style JSON Pointer path to its equivalent for the target specification version.

**Parameters:**

- `path` — The v3-style JSON Pointer (e.g., `#/paths/~1items/get/responses/200/content/application~1json/schema`).
- `targetVersion` — The target OpenAPI specification version.

**Returns:** The equivalent path in the target version, the original path unchanged if no
transformation is needed, or `null` if the construct has no equivalent in the target version.

**Example:**

```csharp
#pragma warning disable OAI020
// v3 path from the walker
var v3Path = "#/paths/~1items/get/responses/200/content/application~1octet-stream/schema";

// Convert to v2 equivalent
var v2Path = OpenApiPathHelper.GetVersionedPath(v3Path, OpenApiSpecVersion.OpenApi2_0);
// Result: "#/paths/~1items/get/responses/200/schema"

// Convert to v3.2 (no transformation needed)
var v32Path = OpenApiPathHelper.GetVersionedPath(v3Path, OpenApiSpecVersion.OpenApi3_2);
// Result: "#/paths/~1items/get/responses/200/content/application~1octet-stream/schema"

// v3-only construct with no v2 equivalent
var serversPath = "#/servers/0";
var v2Result = OpenApiPathHelper.GetVersionedPath(serversPath, OpenApiSpecVersion.OpenApi2_0);
// Result: null
#pragma warning restore OAI020
```

#### `OpenApiValidatorError.GetVersionedPointer(OpenApiSpecVersion targetVersion)`

A convenience method on validation errors that translates the error's `Pointer` property to
the equivalent path for the target specification version.

**Example:**

```csharp
var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
var walker = new OpenApiWalker(validator);
walker.Walk(document);

foreach (var error in validator.Errors)
{
if (error is OpenApiValidatorError validatorError)
{
#pragma warning disable OAI020
var v2Pointer = validatorError.GetVersionedPointer(OpenApiSpecVersion.OpenApi2_0);
#pragma warning restore OAI020
if (v2Pointer is not null)
{
Console.WriteLine($"Error at {v2Pointer}: {validatorError.Message}");
}
}
}
```

### Supported Transformations (v2 target)

| v3 Path Pattern | v2 Equivalent |
|---|---|
| `#/components/schemas/{name}/**` | `#/definitions/{name}/**` |
| `#/components/parameters/{name}/**` | `#/parameters/{name}/**` |
| `#/components/responses/{name}/**` | `#/responses/{name}/**` |
| `#/components/securitySchemes/{name}/**` | `#/securityDefinitions/{name}/**` |
| `.../responses/{code}/content/{mediaType}/schema/**` | `.../responses/{code}/schema/**` |
| `.../headers/{name}/schema/**` | `.../headers/{name}/**` |

### Paths With No v2 Equivalent (returns `null`)

- `#/servers/**`
- `#/webhooks/**`
- `.../callbacks/**`
- `.../links/**`
- `.../requestBody/**`
- `.../content/{mediaType}/encoding/**`
- `#/components/examples/**`, `#/components/headers/**`, `#/components/pathItems/**`,
`#/components/links/**`, `#/components/callbacks/**`, `#/components/requestBodies/**`,
`#/components/mediaTypes/**`

### Why This Is Experimental

The set of path transformations may evolve as edge cases are discovered and additional
specification versions are released. The API surface and behavior may change in future versions
based on community feedback.
46 changes: 46 additions & 0 deletions src/Microsoft.OpenApi/Attributes/ExperimentalAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

// Polyfill for ExperimentalAttribute which is only available in .NET 8+.
// Since the compiler queries for this attribute by name, having it source-included
// is sufficient for the compiler to recognize it.
namespace System.Diagnostics.CodeAnalysis

Check warning on line 7 in src/Microsoft.OpenApi/Attributes/ExperimentalAttribute.cs

View workflow job for this annotation

GitHub Actions / Build

Remove this empty namespace.
{
#if !NET8_0_OR_GREATER
Comment thread
baywet marked this conversation as resolved.
Outdated
/// <summary>
/// Indicates that an API is experimental and it may change in the future.
/// </summary>
/// <remarks>
/// This attribute allows call sites to be flagged with a diagnostic that indicates that an experimental
/// feature is used. Authors can use this attribute to ship preview features in their assemblies.
/// </remarks>
[AttributeUsage(
AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct |
AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property |
AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate,
Inherited = false)]
internal sealed class ExperimentalAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ExperimentalAttribute"/> class,
/// specifying the ID that the compiler will use when reporting a use of the API.
/// </summary>
/// <param name="diagnosticId">The ID that the compiler will use when reporting a use of the API.</param>
public ExperimentalAttribute(string diagnosticId)
{
DiagnosticId = diagnosticId;
}

/// <summary>
/// Gets the ID that the compiler will use when reporting a use of the API.
/// </summary>
public string DiagnosticId { get; }

/// <summary>
/// Gets or sets the URL for corresponding documentation.
/// The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID.
/// </summary>
public string? UrlFormat { get; set; }
}
#endif
}

Check warning on line 46 in src/Microsoft.OpenApi/Attributes/ExperimentalAttribute.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this empty namespace.

See more on https://sonarcloud.io/project/issues?id=microsoft_OpenAPI.NET&issues=AZ2Xwi35HOaBv7t4iEMm&open=AZ2Xwi35HOaBv7t4iEMm&pullRequest=2827
3 changes: 3 additions & 0 deletions src/Microsoft.OpenApi/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
#nullable enable
Microsoft.OpenApi.OpenApiPathHelper
static Microsoft.OpenApi.OpenApiPathHelper.GetVersionedPath(string! path, Microsoft.OpenApi.OpenApiSpecVersion targetVersion) -> string?
Microsoft.OpenApi.OpenApiValidatorError.GetVersionedPointer(Microsoft.OpenApi.OpenApiSpecVersion targetVersion) -> string?
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

namespace Microsoft.OpenApi;
/// <summary>
/// Defines a policy for matching and transforming OpenAPI JSON Pointer path segments
/// between specification versions.
/// </summary>
internal interface IOpenApiPathRepresentationPolicy
{
/// <summary>
/// Attempts to transform the given path segments to the equivalent in the target version.
/// </summary>
/// <param name="segments">The pre-parsed path segments (without the <c>#/</c> prefix).</param>
/// <param name="result">
/// When this method returns <c>true</c>, contains the transformed path or <c>null</c>
/// if the path has no equivalent in the target version.
/// </param>
/// <returns><c>true</c> if this policy handled the path; <c>false</c> to try the next policy.</returns>
bool TryGetVersionedPath(string[] segments, out string? result);
}
Loading
Loading