dotnet/aspnet-api-versioning

Does this work with RESTier?

Tiberriver256 opened this issue · 11 comments

I didn't see any specific documentation about working with RESTier but it does use all the same underlying technologies, so it should work in theory right?

From a purely technical perspective, API versioning could support RESTier. Unfortunately, the routing configuration for OData holistically is not all that extensible. The design has gotten more flexible with the adoption of dependency injection, but there would still be considerable developer work to make the necessary route configurations for API versioning. In fact, if you happen to look at the API versioning source code for OData, a significant part of it is merely reimplementing all of the route configurations.

Honestly, I don't have a deep knowledge of RESTier. I took a peek at their source and it appears that MapRestierRoute wraps over MapODataServiceRoute. The MapODataServiceRoute method is not used by API versioning and it instead provides the similarly named methods MapVersionedODataRoute and MapVersionedODataRoutes, which are API version aware. It don't see why - yet, a flavor of RESTier setup could not be created that could support API versioning.

I'm not opposed seeing a supported flavor of RESTier be supported, but it's quite doubtful at this point in time that I would support it. I'm virtually an army of one on this project and I already support 3 platforms. I'm not sure that I can take on more. Furthermore, from the information I've found there are quite a few flags that would make me hesitant, including:

  • There's no official release; despite calling it General Availability (GA), the released package is still Beta
  • There hasn't been any active development on RESTier for more than two years
  • RESTier currently only supports ASP.NET Web API and not even the current version 7.x+
  • Adoption numbers, based on package downloads, is fairly low
  • Issues no longer seem to be answered, triaged, or otherwise resolved

It would seem that RESTier never got the true green light for GA. It has all the indications that no more work is being done or may ever be done on it again. It might be worth asking the OData team or perhaps even an issue on RESTier itself to see if the project is still active. If it's still active and there is enough interest, I would consider supporting it in a future iteration. Otherwise, it would be up to the RESTier community to create a package that is API version aware, which should be a combination of API versioning for OData and RESTier.

I'm sure that's not the answer you were looking for, but I hope that provides some useful information.

Thank you for the great answer! The OData team continues to insist they are almost back to supporting RESTier. You can read our conversation with that team here:

OData/RESTier#540

I fully understand the response though. Hopefully we can see some action on the project.

Ah … I hadn't see that issue before. It's a pretty long thread, but I went through it. Sounds about right with what I know. The OData team/owners have changed numerous times over the years and it's still not part of ASP.NET any more. There is a team, but I'm not sure how big it is. I know it's not huge and it's been driven by other teams needing the capabilities of OData.

If they can get RESTier to at least have parity with OData on Web API 7.0+, then I can consider supporting it. The large variations in OData implementations has forced me to support only the latest versions because it's just too much work to maintain all the flavors. It's very rare for me to even backport bugs to earlier support OData versions. I'm burning in the support for 3.0 of API Versioning which will push the OData support forward to 7.0+.

Well, it all runs around that Odata needs to start moving out of their slumber and move to the new 2.2 endpoint routing. Then this opens a lot of possibilities down the road to integrate.

Sadly, I am quite negative about the Odata team actually ever going to significantly move out of their slumber. History sadly talks badly about it ;( Still wishing. Like many here I am sold on OData - and stuck with the MS Stack. As bad as it partially is, trying to integrate in typescript is even worse.

I'm inclined to agree. The only real positive note is that the EDM bits (also owned by OData) have been kept up-to-date and are now portable via .NET Standard. Should someone or some team put forth an alternate implementation, they can focus purely on how they want it to work with ASP.NET (e.g. routing, etc).

OData is great protocol, but the MS implementation has been less than stellar. Depending on your requirements for compliance, you can take many parts of the OData, even without the ASP.NET parts and apply them yourself. For example, you don't need to use the OData ASP.NET implementation to extract the entity set from the URL. You could resolve it yourself and look it up in the EDM. Of course, no one really wants to do that, but sometimes that compromise might be better than shoe-horning OData ASP.NET implementation, waiting for a feature request, or waiting for bug fix.

I don't how many or if the are any other TypeScript clients, but if you're looking for one, the old DataJS is probably a good start. It was only by Microsoft (on CodePlex), but is seemingly dead now. I can't remember if it supported v3, v4, or both version of the OData protocol. Regardless, it's open source and a good place to start for anyone that wants to be build a TypeScript client. I used to use it quite a bit and found it quite simple to use.

One more side bar for those that use the OData client generate template with API versioning, the template erroneously assumes that if the URL doesn't end with /$metadata exactly, it should be appended. This means that http://localhost/$metadata?api-version=2.0 ends up becoming http://localhost/$metadata?api-version=2.0/$metadata. It's an easy fix in the template (e.g. remove the URL modification), but FYI for anyone actually using it.

Just thought I'd post back on this and say RESTier is back in active development and has released a couple of release candidates. They are getting very close to the first GA and then will focus on a re-write for .NET core. I opened a discussion on their end for versioning and support.

Hello, my name is Robert McLaws, and I'm one of the project leads for Restier. I don't see any reason why we couldn't ship a NuGet package that bridges the gap between this library and Restier by shipping a .MapVersionedRestier() extension method.

We also refactored how services were added vs routing, so that should also make this a bit easier.

I'll look into it over the break and see if we can ship something by RTM. Thanks!

No problem. Some of the work may (or may not) be predicated by the OData work happening for .NET Core 3.0/3.1. On both the old Web API stack and the (now legacy) IRouter method of routing in ASP.NET Core, API Versioning has to replace/extend the core action selection logic. This has been at odds with OData in the past, which does some of the same things. This is also what drove the OData-specific EnableApiVersioning() extension method because it was the only way to ensure the API Versioning changes came after OData. This requirement, in part, influenced the design of Endpoint Routing (I met with the ASP.NET team a couple of times) and made it possible to extend the action selection rather than replace it. As it still currently stands, I've effectively had to fork a significant portion of the OData routing code to make it support versioning. =/

At its most basic roots, API Versioning doesn't really change anything about routing. It merely allows duplicates routes where duplicate routes would not have been allowed before and disambiguates them by API version. If duplicates still arise (e.g. developer mistake), the behavior should remain unchanged from routing without API Versioning. How API Versioning discovers and manages the versions is a cross-cutting concern that can be provided by attributes or conventions.

As things more specifically apply to the OData implementation, all of the other rules apply and API Versioning additionally creates a single EDM per API Version. This provides clean separation of each EDM and most things continue to work the same or similar to how they worked before (ex: $metadata, but now also with $metadata?api-version=2.0 or whatever versioning method was used). Each EDM is also annotated with the ApiVersionAnnotation so you can tell which version the EDM is for.

Unfortunately, because OData uses a catch-all route template (e.g. {*odataPath}) and then bolts on its own conventions, this adds some additional complexity. Specifically, an OData route is generated per API Version and EDM. There is also a special unversioned route to maintain parity with the 400 behavior or an unmatched API version vs the normal 404 response.

I assume the ask is mostly for .NET Core, but I'm open to supporting the Web API stack too. You can find the .NET Core implementation setup here if you hadn't already seen it. It should look strikingly similar to the built-in OData setup, with additional configuration or hooks. I'm open to other ideas for setup too. I never really liked it, but I went with an approach that was similar to the out-of-the-box OData experience.

Restier does not support .NET Core at all. We are shipping v1 with support for WebAPI2, so we can honor the work that the original team did. Since that tech was started in 2014, it doesn't make sense to carry that into 2020. We can support .NET Core more quickly if we rebuild Restier's interception pipeline so that it properly supports DI.

Ah … ok … so were just talking about the Web API stack. No problem. It's certainly less work in the short run. ;)

Here's the configuration setup for Web API. The majority of things are the same between the platforms. The majority of the work has been making OData's routing API Version aware. There's a ton of unit and acceptance tests if that helps flush out things work. There's also a few sample applications.

Happy to answer any questions or chew on ideas. I'm not all that familiar with RESTier's inner working.

I'm going back and cleaning up old issues. In terms of what this project will do, I think the issue has reached its conclusion. As a one-man project, there's only so much I can facilitate on my own. Had I not already had a deep and long history with OData, it may never have been supported at all.

5.0.0-RC.1 is now available. This version has undergone a complete overhaul of the internal OData setup mechanics. It's simpler and more straight forward than ever before. As it relates to RESTier, the IContainerBuilder extensions required to enable API versioning services are publicly accessible. As proposed above, RESTier would likely need something like MapVersionedRestier which would use a setup similar to the HttpConfiguration.MapVersionedODataRoute extension methods. If you had looked at these in the past, you'll notice that they are vastly simpler and is now able to pipe through to the core OData implementation. There may be a few things need to setup the correct routing conventions, etc, but all the pieces are there and it should be straight forward.

API Versioning replaces the following services in Web API:

  • IHttpControllerSelector
  • IHttpActionSelector
  • IApiExplorer (if using API explorer extensions)

I don't see those being changed by RESTier so it shouldn't be affected. The changes to the way ODataQuerySettings are registered might affect the way API Exploration works or otherwise reports query options. These can be addressed by using the query option configuration conventions for the versioning API Explorer extensions or it can be handled in your OpenAPI/Swagger generator of choice.

I'm happy to provide guidance, input, or potentially even make changes to support anyone's effort to bring versioning to RESTier. My best estimation is that versioning is possible with minimal effort. If ASP.NET Core is ever supported, the interaction and APIs to connect versioning to OData is very similar.

Aside: The RC label is to allow for a little burn-in to 5.0 before officially publishing. That should happen within the next 2 weeks from this post.

Thanks again for the interest, but this isn't a project I can take on here. Feel free to continue asking questions on this issue if there are any. Thanks.