JsonApiDotNetCore icon indicating copy to clipboard operation
JsonApiDotNetCore copied to clipboard

How to handle API versioning

Open rsmith8917 opened this issue 2 years ago • 1 comments

SUMMARY

I'm looking for some guidance on how to handle API versioning using the JsonApiDotNetCore library. As an example, let's say I have a Book entity and I currently have a series of endpoints defined for CRUD operations on Books (i.e. /api/v1/books). Now let's say I'd like to make some changes to the Book entity and would like to reflect this in a new endpoint (i.e. /api/v1.1/books) while retaining the existing v1 endpoint as much as possible. I could create a new BookV1p1 resource class and a new controller, but now I have two model classes that would be mapped to two different tables via EF Core. What I would like to achieve is to be able to make the desired changes to the EF Core model and create two different controllers for interacting with this model (/api/v1.1/books and /api/v1/books). /api/v1.1/books would use the new Book EF Core model directly, whereas /api/v1/books would perform some conversions from the old Book definition to the new one. I was reading through the Extensibility section of the documentation but was struggling to identify what the appropriate layer to handle this case is. Any help pointing me in the right direction here would be greatly appreciated.

VERSIONS USED

  • JsonApiDotNetCore version: 5
  • ASP.NET Core version: 6
  • Entity Framework Core version: 6
  • Database provider: MySQL (Pomelo EF Core Provider)

rsmith8917 avatar Aug 08 '22 14:08 rsmith8917

Hi @rsmith8917,

As far as I'm aware, API versioning was never really thought through for JsonApiDotNetCore. Over the years, we've seen comments from users in issues and the chat about their approaches, but it really depends on the use case and what kinds of changes in versions are to be expected.

Stripe's approach to API versioning is described at https://stripe.com/blog/api-versioning. I like the idea of migrations, which could be added to JsonApiReader/Writer. They would transform the incoming JSON body to the latest version and vise-versa. I'd recommend using a HTTP header or query string to pass the version, so you won't need to adapt routing. This leaves the controllers, resources and DB mappings unchanged.

Another solution would be to run the transforms in a reverse proxy such as YAST.

It would be interesting to gather a list of versioning changes and think about a universal solution in JsonApiDotNetCore. Things that come to mind:

  • Attributes
    • Adding new attributes
    • Merging/splitting of attributes
    • Changing the data type or requiredness of attributes
    • Renaming attributes
  • Relationships...?
  • Resources...?
  • Endpoints...?

Atomic operations is a separate concern: it codifies requests in a different way. If routes are involved, LinkBuilder probably requires changes to accommodate the version in the URLs. If new endpoints or relationships must be blocked from older versions, JsonApiMiddleware likely needs to handle that.

Then there's query strings, such as filters and sorting. What should happen when trying to filter or sort on an attribute that was split-up in the latest version? There's no generic mechanism to produce a WHERE clause for that.

All in all, this is hard to design without a clear scope with good use cases.

bkoelman avatar Aug 10 '22 01:08 bkoelman

@rsmith8917 Any thoughts about the above?

bkoelman avatar Sep 28 '22 03:09 bkoelman

Closing due to inactivity.

bkoelman avatar Oct 27 '22 00:10 bkoelman