API版本控制 .Net Core > 不正确的支持/已弃用版本报告,忽略MapToApiVersion

huangapple go评论67阅读模式
英文:

API Versioning .Net Core > Incorrect Supported/Deprecated Versions Reported Ignoring MapToApiVersion

问题

I have a controller class that supports operations for versions 1 and 2, as shown below:

[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpGet, Route("testmethod")]
    public string TestMethod()
    {
        return "Test method call successful";
    }

    [MapToApiVersion("2.0")]
    [HttpGet, Route("addedin2")]
    public string AddedIn2()
    {
        return "AddedIn2";
    }
}

The operation addedin2 was introduced in version 2 as specified with the attribute MapToApiVersion. While calling the API operation with version as 1.0 correctly returns a 400 status code, but the Api-Supported-Versions still shows 1.0 and 2.0 as the supported versions. Why is this so? Is this a bug in the library, or is there something wrong with my understanding of the usage of the attribute MapToApiVersion?

If I create a separate controller class for API version 2, the Api-Supported-Versions is returned correctly as shown below. The only problem, though, is that the unchanged methods of version 1.0 need to be duplicated in version 2.0, which I want to avoid.

[ApiVersion("1.0")]
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpGet, Route("testmethod")]
    public string TestMethod()
    {
        return "Test method call successful";
    }
}

[ApiVersion("2.0")]
[Route("api/test")]
[ApiController]
public class TestController2 : ControllerBase
{
    [HttpGet, Route("testmethod")]
    public string TestMethod()
    {
        return "Test method call successful";
    }

    [HttpGet, Route("addedin2")]
    public string AddedIn2()
    {
        return "AddedIn2";
    }
}
英文:

I have a controller class that supports operations for versions 1 and 2, as shown below:

[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
    {
        
        [HttpGet, Route("testmethod")]
        public string TestMethod()
        {
            return "Test method call successful";
        }

        [MapToApiVersion("2.0")]
        [HttpGet, Route("addedin2")]
        public string AddedIn2()
        {
            return "AddedIn2 ";
        }
    }

The operation addedin2 was introduced in version 2 as specified with the attribute MapToApiVersion. While calling the API operation with version as 1.0 correctly returns 400 status code, but the Api-Supported-Versions still shows 1.0 and 2.0 as the supported versions. Why this is so? Is this a bug in the library, or there is something wrong with my uderstanding of usage of attribute MapToApiVersion?

API版本控制 .Net Core > 不正确的支持/已弃用版本报告,忽略MapToApiVersion

If I create a separate controller class for API version 2, the Api-Supported-Versions is returned correctly as shown below. The only problem though, the unchanged methods of version 1.0 need to be duplicated in version 2.0 which I want to avoid.

[ApiVersion("1.0")]
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
        
    [HttpGet, Route("testmethod")]
    public string TestMethod()
    {
        return "Test method call successful";
    }
}

[ApiVersion("2.0")]
[Route("api/test")]
[ApiController] 
public class TestController2 : ControllerBase
{
    [HttpGet, Route("testmethod")]
    public string TestMethod()
    {
        return "Test method call successful";
    }

    [HttpGet, Route("addedin2")]
    public string AddedIn2()
    {
        return "AddedIn2 ";
    }
}

API版本控制 .Net Core > 不正确的支持/已弃用版本报告,忽略MapToApiVersion

答案1

得分: 1

您所观察到的是正确且预期的行为。API版本的排序经常被误解。虽然可以为特定的端点设置API版本,但意图是为API版本进行版本控制。Web API通常包含多个相关的端点。例如,Order API可能至少有一个用于GETPOSTPUTDELETE方法的操作。这些方法集体构成了API,并具有一组版本。当客户端启用或开始使用API时,它们不会对齐到GET /order/42,而是对整套可用的API方法进行启用。

API版本控制按逻辑API将API版本进行汇总。实际上没有其他可靠的方法。按路由模板进行分组是不一致的。例如,/order/{id}/order/{id:int}在语义上是等效的,但它们并不相同。现在考虑类似/order/{id}/items的情况。这是否属于_Order_ API还是其他API的一部分?从URL的角度来看,这是未知的,是一项实现细节。按逻辑名称分组,无论是隐式还是显式,都更准确地传达了API作者的意图。当您使用控制器时,API版本将按控制器的名称进行汇总。按照惯例,TestController的API的逻辑名称为Test。所有具有此名称的控制器、操作和端点都会被汇总在一起。您在第二个定义中看到的报告的版本分开的原因是因为名称不再匹配。默认的ASP.NET Core约定通过删除Controller后缀来定义名称。因此,如果您将控制器命名为TestController2,约定将被打破并且会被不同地合并。如果您将控制器命名为Test2Controller,则会观察到与原始实现相同的结果。这是因为API版本控制提供了一项额外的约定,还会删除任何尾随的数字。这意味着TestControllerTest2Controller都将具有名称Test。在某些罕见情况下,您可能希望保留尾随的数字(例如S3Controller)。此高级行为可以通过IControllerNameConvention服务进行自定义,该服务具有多个内置实现。

报告API版本的目的是宣传API支持的和已弃用的版本,而不是特定的端点。有许多其他信息无法通过一个或两个简单的HTTP标头传达。支持的API版本不表示支持哪些HTTP方法。支持这一点的更好方法是实现一个OPTIONS端点。

例如,版本中性的端点可能会指示所有API版本:

OPTIONS /order HTTP/2
Host: localhost
HTTP/2 200 OK
Allow: GET, POST, PUT, DELETE
Api-Supported-Versions: 1.0, 2.0

这表示所有版本中存在哪些方法和版本。您还可以选择具有特定版本的端点以缩小范围:

OPTIONS /order?api-version=1.0 HTTP/2
Host: localhost
HTTP/2 200 OK
Allow: GET
Api-Supported-Versions: 1.0, 2.0

这表示特定版本允许哪些方法,但指示存在其他版本。

就全面记录和发现API而言,OpenAPI(以前称为Swagger)是一个更好的选择;但是,报告API版本仍然很有用。例如,客户端如何知道它们正在与已弃用的API版本通信?客户端如何发现新的API版本可用?新的Asp.Versioning.Http.Client提供了支持这些场景的扩展。当发生“有趣”的情况时,将触发事件以进行反应。这为客户端提供了连接遥测和警报的能力,可以指示是否正在使用已弃用的API版本等情况。如果API支持新的“日落政策”,也会报告此信息。这可以告诉客户端已弃用的API版本将永久日落,并提供到API政策的链接。

英文:

What you are observing is the correct and expected behavior. The collation of API versions is often misunderstood. While it is possible to have API versions for a specific endpoint, the intent is to version an API. An web API typically consists of more than one, related endpoint. For example, the Order API likely has at least one operation for the methods GET, POST, PUT, and DELETE. These are collectively the API and have a set of versions. When a client onboards or starts using the API, they do not align to GET /order/42, they onboard to the entire set of available API methods.

API Versioning collates API versions by logical API. There is honestly no other reliable way. Grouping by route template is inconsistent. For example, /order/{id} and /order/{id:int} are semantically equivalent, but they are not the same. Now consider something like /order/{id}/items. Is this part of the Order API or some other API? From a URL standpoint, it's unknown and an implementation detail. Grouping by logical name, be it implicit or explicit, more accurately conveys the API author's intentions. When you use controllers, API versions are collated by the name of the controller. By convention, the logical name of the API for TestController is Test. All controllers, actions, and endpoints with this name are collated together. The reason you saw the reported versions split apart in your second definition is because the names no longer match. The default ASP.NET Core convention defines names by dropping the Controller suffix. Since you named your controller TestController2, the convention was broken and collated differently. Had you named the controller Test2Controller, you would observe the same results as the original implementation. This is because API Versioning provides an additional convention which also strips off any trailing numbers. This means that TestController and Test2Controller will both have the name Test. There are rare cases where you might what to keep the trailing number (ex: S3Controller). This advanced behavior can be customized via the IControllerNameConvention service, which has several built-in implementations.

The purpose of reporting API versions is to advertise the supported and deprecated versions for an API, not a specific endpoint. There is a lot of additional information that cannot be conveyed in one or two simple HTTP headers. A supported API version does not indicate which HTTP methods are supported. A better way to support that would be to implement an OPTIONS endpoint.

For example, a version-neural endpoint might indicate all API versions:

OPTIONS /order HTTP/2
Host: localhost
HTTP/2 200 OK
Allow: GET, POST, PUT, DELETE
Api-Supported-Versions: 1.0, 2.0

This indicates which methods and versions exist across all versions. You could optionally have a version-specific endpoint to narrow things down:

OPTIONS /order?api-version=1.0 HTTP/2
Host: localhost
HTTP/2 200 OK
Allow: GET
Api-Supported-Versions: 1.0, 2.0

This indicates which methods are allowed for a specific version, but indicates there are additional versions available.

In terms of documenting and discovering an API comprehensively, OpenAPI (formerly Swagger) is a much better option; however, reporting API versions is still useful. For example, how would a client know that they are talking to a deprecated API version? How would a client ever discover that a new API version is available? The new Asp.Versioning.Http.Client provides extensions to support these scenarios. When an interesting scenario occurs, an event is triggered for reaction. This affords the ability for a client to wire up telemetry and alerts that can indicate when something like a deprecated API version is being used. If the API supports the new sunset policy, that information is also reported. This can tell the client when a deprecated API version will be permanently sunset as well as emit links to the API's policies.

huangapple
  • 本文由 发表于 2023年6月8日 17:43:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76430558.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定