Version Restler without copying entire previous API version - restler

I'm using Restler 3.0.0-RC6 and I'm confused on versioning. I have a v1 version (in a namespace) and now I need to make a breaking API change, so I want to create a v2 dir/namespace. However, I only need a couple of the API methods to change. How do I just modify those methods and not copy over the entire v1 directory?

If you want to serve a an API Class for multiple versions of the API, just implement iProvideMultiVersionApi interface which is basically adding a static function which returns the highest supported version. If you want to always support till the latest API version, You can add the following function to your API class (in Restler RC5)
/**
* Maximum api version supported by the api class
* #return int
*/
public static function __getMaximumSupportedVersion()
{
return Scope::get('Restler')->_apiVersion;
}

Related

API Versioning in .NET Core - AssumeDefaultVersionWhenUnspecified

I'm looking into adding versioning to an existing API we have. We are embedding the version in the URL.
The requirement for the versioning is that it should be easy to add a new version, but not everything changes and we don't want to go through all controllers and add new version attributes when we get a new version. Is there any way to tell Microsoft.AspNetCore.Mvc.Versioning that a particular method should be available regardless of versions?
I have tried decorating my method with both with the version:apiVersion and with just a basic route.
[Route("v{version:apiVersion}/customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
My configuration is as such (the version number 3 is just for testing purposes):
services.AddApiVersioning(config =>
{
config.DefaultApiVersion = new ApiVersion(3, 0);
config.AssumeDefaultVersionWhenUnspecified = true;
config.ReportApiVersions = true;
});
When calling the endpoint with this configuration I get "The HTTP resource that matches the request URI 'http://{{host}}/api/customers/{customer}/estates/{estate}/meters/{meter}-{installation}/consumption/detail' is not supported
As soon as I add the [ApiVersion("3.0")] attribute everything works. But my thought was that if I currently run on version 2, but changes to other parts of the API warrant a new version and the default version of the API, I don't want to have to go this controller and "bump" the version. It should just continue to respond, unless I specify something specific.
If I change the AssumeDefaultVersionWhenUnspecified to false, I get an "An API version is required, but was not specified." But I expected that it would just grab the route without the version?
I have read about the limitations here: https://github.com/Microsoft/aspnet-api-versioning/wiki/Known-Limitations#url-path-segment-routing-with-a-default-api-version
But it doesn't seem to work.
Setting AssumeDefaultVersionWhenUnspecified = true is a highly abused feature. This is only meant to facilitate backward compatibility. Once you opt into API Versioning, all API controllers have some implicit or explicit API version. Assuming a version provides a mechanism to handle the "original", unnamed version that would otherwise break existing clients that don't know to include an API version in requests.
"Is there any way to tell Microsoft.AspNetCore.Mvc.Versioning that a particular method should be available regardless of versions?"
Yes, but I'm not entirely sure that is what you're looking for. An API can be version-neutral, which means it will accept any and all API versions, including none at all. This is useful for certain types of APIs such as a /ping health check or DELETE, which typically do not change over time. Such an API can be decorated with [ApiVersionNeutral]. This can be for all APIs on a controller or a specific action. Note that once you choose this path, "there can be only one."
There is not a complete picture of your setup. It appears that you are adding API versioning to an existing set of APIs. One of the primary purposes of DefaultApiVersion is to set what the default API version should be when no other information is available. If you applied no API versions whatsoever - for example, using attributes, then this would be the implicit API version of all APIs. This prevents you from having to retrofit all of your existing controllers and code. What's less obvious is that once you apply any explicit API version, then the implicit rule is ignored. This ensures that implicit versions can be sunset. The default version often does not matter. It's simply a way for you to indicate what the initial API version originally was. It's most relevant when grandfathering in existing APIs.
Given your configuration:
// implicitly 3.0 because DefaultApiVersion = 3.0 and there
// are no explicit versions from attributes or conventions
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
public class CustomerController : ControllerBase
{
}
Grandfathered controller with implicit versioning
// explicitly 2.0 due to attributes; DefaultApiVersion is ignored
[ApiVersion("2.0")]
[Route("v{version:apiVersion}/customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
public class CustomerController : ControllerBase
{
}
Controller with explicit versioning
With the exception of supporting the backward compatible, original API version, all APIs versions are explicit and discrete; this is by design. Fuzzy matching will not work in a predictable way so it's important to have exact matches.
You seem to be describing API version interleaving - e.g. multiple API versions implemented on a single controller implementation. I presume it might look like:
[ApiVersion("2.0")]
[ApiVersion("3.0")]
[Route("v{version:apiVersion}/customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
public class CustomerController : ControllerBase
{
// implicitly maps to 2.0 from the controller, but does not
// match 3.0 because there is an explicit 3.0 mapping
[HttpGet]
public IActionResult Get(
string customerId,
int estateId,
string meterNumber,
string installationId ) => Ok();
// explicitly maps to 3.0 only
[MapToApiVersion("3.0")]
[HttpGet]
public IActionResult GetV3(
string customerId,
int estateId,
string meterNumber,
string installationId ) => Ok();
// explicitly maps to 3.0 only
// a 2.0 request produces 405
[MapToApiVersion("3.0")]
[HttpPut]
public IActionResult Put(
string customerId,
int estateId,
string meterNumber,
string installationId
[FromBody] ComsumptionDetail detail ) => Ok();
}
Controller with version interleaving
The DefaultApiVersion can only apply a single, implicit API version. This means that no interleaving with it can ever occur. Once you start explicitly adding versions, you must also start including the implicit version because there is no other way to indicate that the implicit version should no longer be matched.
In terms of route definitions and API version mapping, there are several methods that can be used to minimize code churn. The VersionByNamespaceConvention is a built-in convention you can apply which will derive an API version from the .NET namespace of the controller type. This can make it really easy to add, remove, and organize controllers with their API versions. They can also use interleaving because the mapping is additive, but that may be confusing to maintain. You can define your own conventions as well.
Double-route registration is a consequence of versioning by URL segment. It is the least RESTful method of versioning because it violates the Uniform Interface constraint. No other method of versioning has this issue. I advise against floating the default route and API version mapping because you are very likely to break clients at some point. If you're only using double-routes for backward compatibility of your original API version, then you should be fine. When you eventually create new controllers for future API versions, you'll only have one route with the API version in the template.

API Versioning in dotnet core

I am working on APIs in dotnet core 2.2 and I'd like to version my API.
I'm looking for some solutions except:
Routing method (api/v1/controller, api/v2/contoller)
Routing method using APIVersioning package, (api/v{version: apiVersion}/contoller})
I want to know if there is any other solutions in which I don't have to change the route attribute? I might be completely wrong but can I use middleware? Like, map delegate to map the the incoming requests (based on v1, v2 it carries) to its right controller?
I'll highly appreciate any feedback and suggestions.
You can use the APIVersioning package and configure it so it selects the version based on the HTTP Header.
services.AddApiVersioning(c =>
{
c.ApiVersionReader = new HeaderApiVersionReader("api-version");
}
And then you can use the [ApiVersion] attribute on your controllers.
Can you use custom middleware - yes; however, be advised that endpoint selection is typically much more involved. The routing system provides extension and customization points, which is exactly what API Versioning does for you. Creating your own versioning solution will be a lot more involved than having to add a route template parameter.
If you're going to version by URL segment, then API Versioning requires that you use the ApiVersionRouteConstraint. The default name is registered as apiVersion, but you can change it via ApiVersioningOptions.RouteConstraintName. The route parameter name itself is user-defined. You can use whatever name you want, but version is common and clear in meaning.
Why is a route constraint required at all? API Versioning needs to resolve an API version from the request, but it has no knowledge or understanding of your route templates. For example, how would ASP.NET know that the route parameter id in values/{id:int} has be an integer without the int constraint? Short answer - it doesn't. The API version works the same way. You can compose the route template however you want and API versioning knows how and where to extract the value using the route constraint. What API versioning absolutely does not do is magic string parsing. This is a very intentional design decision. There is no attempt made by API Versioning to try and auto-magically extract or parse the API version value from the request URL. It's also important to note that the v prefix is very common for URL segment versioning, but it's not part of the API version. The approach of using a route constraint negates the need for API Versioning to worry about a v prefix. You can include it in your route template as a literal, if you want to.
If the issue or concern is having to repeatedly include the API version constraint in your route templates, it really isn't any different than including the api/ prefix in every template (which I presume you are doing). It is fairly easy to remain DRY by using one of the following, which could include the prefix api/v{version:apiVersion} for all API routes:
Extend the RouteAttribute and prepend all templates with the prefix; this is the simplest
Roll your own attribute and implement IRouteTemplateProvider
Ultimately, this requirement is yet another consequence of versioning by URL segment, which is why I don't recommend it. URL segment versioning is the least RESTful of all versioning methods (if you care about that) because it violates the Uniform Interface constraint. All other out-of-the-box supported versioning methods do not have this issue.
For clarity, the out-of-the-box supported methods are:
By query string (default)
By header
By media type (most RESTful)
By URL segment
Composition of n methods (ex: query string + header)
You can also create your own method by implementing the IApiVersionReader.
Attributes are just one way that API versions can be applied. In other words, you don't have to use the [ApiVersion] attribute if you don't want to. You can also use the conventions fluent API or create your own IControllerConvention. The VersionByNamespaceConvention is an example of such a convention that derives the API version from the containing .NET namespace. The methods by which you can create and map your own conventions are nearly limitless.

Azure Function API Versioning - How to structure my code?

I have created a demo microservices application implemented with the help of Azure Function Apps. For separation of concerns, I have created an API Layer, Business Layer, and a Data Layer.
The API layer, being the function app, calls the business layer which implements the business logic while the data layer implements logic for storing and retrieving data.
After considerable thought, I have decided to use query-based API versioning for my demo.
The question I have is,
What is the best way to organize my code to facilitate this? Is there any other way to organize my code to accommodate the different versions apart from using different namespaces / repos?
As of now, I've created separate namespaces for each version but this has created a lot of code duplication. Also after getting it reviewed by some of my friends, they raised the concern that If separate namespaces are being used I would be forcing legacy systems to change references to the new namespace if they need to update which is not recommended.
Any help would be appreciated.
The simplest way to implement versioning in Azure Functions is using endpoints. The HttpTrigger Attribute allows the definition of a custom route where you can set the expected version.
// Version 1 of get users
[FunctionName(nameof(V1UserList))]
public static IEnumerable<UserModel> V1UserList(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "v1/users")]HttpRequest req, ILogger log)
{
}
// Version 2 of get users
[FunctionName(nameof(V2UserList))]
public static IEnumerable<UserModel> V2UserList(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "v2/users")]HttpRequest req, ILogger log)
{
}
When deploying each version in isolation a router component is required to redirect requests to the correct API endpoint.
The router component can be implemented in Azure using different services, such as:
Azure Function Proxies : you can specify endpoints on your function app that are implemented by another resource. You can use these proxies to break a large API into multiple function apps (as in a microservice architecture), while still presenting a single API surface for clients.
API Management :Azure API Management supports importing Azure Function Apps as new APIs or appending them to existing APIs. The process automatically generates a host key in the Azure Function App, which is then assigned to a named value in Azure API Management.
Sample code for Versioning APIs in Azure Functions

AspNetCore 2.0 + signalR 1.0.0 alpha2 add pipeline or middleware

In an older version of SignalR and .NetFreamwork i used the class inherit the class HubPipelineModule like :
public class IsConnectedPipeLine : HubPipelineModule
{
protected override bool OnBeforeIncoming(IHubIncomingInvokerContext context)
{
if (context.MethodDescriptor.Name == "GetToken")
return true;
return ChatIdentity.CheckToken(context.Hub.Context.GetCurrentUserToken());
}
}
Now i want to start developing in .NetCore 2.0 and SignalR 1.0.0 alpha 2
but I do not know how to implement pipe line, middleware or something like costum ActionAttribute in Web API controller, i do not care how, basically i need the OnBeforeIncoming functionality.
I searched and found only this article but it is very old and not for new versions.
Summarizing what is listed here and where this chain of posts leads.
Here is the proposal that was eventually created and used for net core signalr for similar effect to the HubPipelineModule
and here is a link to documentation on it
and if you're curious... Here's documentation on filters in general
If you're like me, you'll find this section particularly helpful for writing your own filters
Exception catching filters
In my own experience I had a lil scare figuring out how to use it, since I was on net core 3.1 instead of 5.0. 5.0 has the AddFilter call available.

API modularization in Restlet

I have developed a web application based on Restlet API. As I am adding more features over time, I need sometimes to reuse similar group of REST API under different endpoints, which provides slightly different context of execution (like switching different instances of databases with same schema). I like to refactor my code to make the API reusable and reuse them at different endpoints. My initial thinking was to design an Application for each reusable API and attach them on the router:
router.attach("/context1",APIApplication.class)
router.attach("/foo/context2",APIApplication.class)
The API should be agnostic of configuration of the REST API. What is the best way to pass context information (for example the instance of database) to the Application API? Is this approach viable and correct? What are the best practices to reuse REST API in Restlet? Some code samples would be appreciated to illustrate your answer.
Thanks for your help.
I have see this basic set-up running using a Component as the top level object, attaching the sub applications to the VirtualHost rather than a router, as per this skeleton sample.
public class Component extends org.restlet.Component
{
public Component() throws Exception
{
super();
// Client protocols
getClients().add(Protocol.HTTP);
// Database connection
final DataSource dataSource = InitialContext.doLookup("java:ds");
final Configuration configuration = new Configuration(dataSource);
final VirtualHost host = getDefaultHost();
// Portal modules
host.attach("/path1", new FirstApplication());
host.attach("/path2", new SecondApplication(configuration));
host.attach("/path3", new ThirdApplication());
host.attachDefault(new DefaultApplication(configuration));
}
}
We used a custom Configuration object basically a pojo to pass any common config information where required, and used this to construct the Applications, we used separate 'default' Contexts for each Application.
This was coded originally against restlet 1.1.x and has been upgraded to 2.1.x via 2.0.x, and although it works and is reasonably neat there may possibly be an even better way to do it in either versions 2.1.x or 2.2.x.