1

In one of our existing .net core web api (REST) end point, one of its property value in response payload is email address which will be changed to alphanumeric id shortly. This change in response payload will break existing integration.

This breaking change impact can be addressed by introducing version to api saying that only v2 version will alphanumeric id in its response payload otherwise v1 version will keep rendering email address in its response payload but is there any other alternative solution to avoid broken existing integration even after introducing the change in existing response payload structure

Existing response payload structure:

{
  customerid: name@testdomain.com
}

Future response payload structure:

{
  customerid: 1123acbd56
}
191180rk
  • 735
  • 2
  • 12
  • 37
  • You can add a optional parameter to enable the change. – vernou Sep 10 '20 at 16:13
  • Sorry for the ignorance, can you explain bit more with sample please – 191180rk Sep 10 '20 at 16:20
  • JSON does not have a data type for email or alphanumeric values. From a client's perspective, both values are **string**. A client should **never** assume anything about the format of these values. `customerid` != email. This is a problem for the client if they are doing that. You will have to evaluate the weight of trying to support a client doing this. There are several possible solutions, several of which have already been provided. – Chris Martinez Sep 16 '20 at 20:38
  • please list out those several possible solutions you have mentioned above. – 191180rk Sep 18 '20 at 13:49
  • Some additional context is required to provide guidance, which is why I did not provide a complete answer. In the strictest of sense, there is **no** breaking change between `v1` and `v2` as you've described. Both versions have the `customerid` and both are of type string. However, if one or more clients are making an assumption about it being an email address, it may be a problem. That is a judgement call. It would be no different than if `customerid` were a GUID. In the strictest sense, the contract can only specify that it's a string. – Chris Martinez Oct 06 '20 at 18:51
  • A taste of other possibilities are variants of media types as suggested below. You could have something like `application/json; id=alpha` and `application/json; id=email`. When otherwise unspecified `application/json` would imply `application/json; id=email`, which is the existing format. – Chris Martinez Oct 06 '20 at 18:53

1 Answers1

1

You can achieve this by creating a AcceptHeaderAttribute and pass Accept:[attrbute value]

Like, in the below code, I create an AcceptHeaderAttribute

[AttributeUsage(AttributeTargets.Method)]
    public class AcceptHeaderAttribute : Attribute, IActionConstraint
    {
        private readonly string _acceptHeader;
        public AcceptHeaderAttribute(string acceptHeader)
        {
            _acceptHeader = acceptHeader;
        }
        public int Order { get; set; }

        public bool Accept(ActionConstraintContext context)
        {
            return context.RouteContext.HttpContext.Request.Headers["Accept"].Any(x => x.IndexOf(_acceptHeader) >= 0);
        }
    }

And here is the use,

[HttpGet]
        public User GetUserName()
        {
            return new User { Name = "Abcd" };
        }

        [HttpGet]
        [AcceptHeader("app/vnd.user")]
        public User GetUserEmail()
        {
            return new User { Name = "XYZ@ABCD.com" };
        }

And here is fiddler response

enter image description here

Vivek Bani
  • 3,703
  • 1
  • 9
  • 18
  • Going by this reference https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept . Accept header are meant to specify MIME types like text/html, application/xhtml+xml etc. Arent we violating principle here with above example? BTW app/vnd.user is random value or its by some standard/convention? – 191180rk Sep 10 '20 at 17:50
  • vnd is for vendor. it should be application/vnd.newuser. To save time I wrote app/vnd.user. Please check thi Article: https://jacobbednarz.com/posts/using-accept-header-for-http-api-versioning – Vivek Bani Sep 10 '20 at 19:10
  • Reading your article clears up few things. But still is there any reason you have preferred "Accept" header to do this validation rather than introducing custom header starts with "X-" ? Also for any reason "Accept" header approach better then appending queryparameter? – 191180rk Sep 11 '20 at 05:36
  • You scenario is like API versioning. API versioning can be done by query param, custom request header, url, accept header. When use query param to target a specific api version, confusion arises in longer term as Query param will never tell you which version of the api you are targeting and you may required to inspect api code. Now the end goal is not to break existing client. So once you introduce custom header, change to the header is not very easy. Like if you introduce, x-new-user, in next version you cannot make it x-first-user as this will break existing clients. – Vivek Bani Sep 11 '20 at 10:20
  • You will be creating a tight coupling with custom header key. With url api versioning, existing clients also need to start using new url structure if they are using non-versioning one. Whereas Acept header is the easiest to change in longer term, reduced testing effort. – Vivek Bani Sep 11 '20 at 10:20
  • I would argue that using a media like this **would** be a violation because the payload is JSON (application/json); you don't need a whole new media type. You _could_ use a media type parameter to address the problem without violating the way things are meant to work. For example, you might use `Accept: application/json; id=alpha` where the default might be `id=email`. There are many possible solutions, but this would inform the server how to encode the `customerid`. – Chris Martinez Sep 16 '20 at 20:34
  • https://apisyouwonthate.com/blog/api-versioning-has-no-right-way https://nordicapis.com/introduction-to-api-versioning-best-practices/ – Vivek Bani Sep 16 '20 at 23:28