Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asp.Versioning.Http package support #352

Closed
rsr-maersk opened this issue Nov 27, 2022 · 22 comments
Closed

Asp.Versioning.Http package support #352

rsr-maersk opened this issue Nov 27, 2022 · 22 comments
Labels
enhancement New feature or request implemented requested feature has been implemented

Comments

@rsr-maersk
Copy link

rsr-maersk commented Nov 27, 2022

HI

Thanks for the awesome package. Its awesome.

we add versions to our Apis via api header:

services.AddApiVersioning(options =>
        {
            options.AssumeDefaultVersionWhenUnspecified = true;
            options.DefaultApiVersion = ApiVersion.Default;
            options.ReportApiVersions = true;
            options.ApiVersionReader = new HeaderApiVersionReader("api-version");
        });

The API versioning on https://fast-endpoints.com/docs/api-versioning#deprecate-an-endpoint uses a path for the versioning.
For fast endpoints we are also using the "Configure()" override. How can we utilize our version header for apis and using the Configure option. The "Version()" override does not appear to work :-/

Would be awesome if it fastendpoints could support https://github.com/dotnet/aspnet-api-versioning

Thanks again..

@dj-nitehawk
Copy link
Member

Asp.Versioning.Http package is currently not supported. somebody who's familiar with the internal workings of that package would have to make a contribution.

as for our existing implementation of versioning, will look in to the possibility of adding header support as soon as i get a chance. if someone reading this wants to have a crack at adding header support to our versioning, please go ahead and submit a PR.

thanks!

@dj-nitehawk dj-nitehawk changed the title Using HeaderApiVersionReader with fast endpoints Asp.Versioning.Http package support Nov 27, 2022
@dj-nitehawk dj-nitehawk added enhancement New feature or request up for grabs community contribution is needed for this issue labels Nov 27, 2022
@rsr-maersk
Copy link
Author

The main point though is, that the versioning needs to support the HeaderApiVersionReader.
It is just as normal for Api Versioning in the header, equally to a path prefix

@MichaelHochriegl
Copy link
Contributor

MichaelHochriegl commented Apr 18, 2023

Is there anything new on this front? Versioning by header would be my goto solution as well.
An integration with Asp.Versioning.Http would be really nice but I don't think that I'm skilled enough in it to provide support for FE.

How should it work in regards to the routeBuilder.BuildRoute(def.Version.Current, route, def.OverriddenRoutePrefix); in MainExtensions.cs. I reckon that there will be a couple of "hidden" problems with multiple routes?

EDIT: How would you envision the contribution to look like? In what "form" should Asp.Versioning.Http/Asp.Versioning.WebApi be brought to FE?

@dj-nitehawk
Copy link
Member

dj-nitehawk commented Apr 18, 2023

ideally we should look at providing header support for our existing versioning system instead of relying on a third-party package which is not even maintained by microsoft anymore.

so if you wanna have crack at implenting that, do go ahead...
as for how, i have no idea. i need to sit down and study the versioning code again.
the amount of free time needed for this task is nowhere to be found anytime soon for me unfortunately 🫤

@dj-nitehawk

This comment was marked as outdated.

@dj-nitehawk dj-nitehawk added wip work is in progress and removed up for grabs community contribution is needed for this issue labels Apr 24, 2023
@MichaelHochriegl
Copy link
Contributor

Thanks! This looks awesome, still have to look at the actual implementation that you chose, I had planned to give it a go on the weekend but now more time for other projects.

@zfchai

This comment was marked as outdated.

@dj-nitehawk

This comment was marked as outdated.

@zfchai

This comment was marked as outdated.

@zfchai

This comment was marked as off-topic.

@zfchai

This comment was marked as off-topic.

@dj-nitehawk

This comment was marked as off-topic.

@candoumbe
Copy link

Good to see some work being done on this area !
I just forked the project and was about to ask where tests related to handling versions are (if any).

Well done !

@dj-nitehawk
Copy link
Member

@candoumbe no tests yet. i'm trying to wrap up this functionality into a FastEndpoints.AspVersioning package for ease of use. let's see how that goes.

@candoumbe
Copy link

@candoumbe no tests yet. i'm trying to wrap up this functionality into a FastEndpoints.AspVersioning package for ease of use. let's see how that goes.

Yeah of course, I was talking about tests for the "current" implementation of Versioning (and not the one in WIP).

@dj-nitehawk
Copy link
Member

dj-nitehawk commented Apr 25, 2023

@candoumbe integration tests like these are dispersed throught 🤐

public async Task AdminLoginThrottling()
{
var guest = EndToEndTestFixture.CreateNewClient();
guest.DefaultRequestHeaders.Add("X-Custom-Throttle-Header", "TEST");
var successCount = 0;
for (var i = 1; i <= 6; i++)
{
var (rsp, res) = await guest.POSTAsync<
Admin.Login.Endpoint_V1,
Admin.Login.Request,
Admin.Login.Response>(new()
{
UserName = "admin",
Password = "pass"
});
if (i <= 5)
{
rsp?.StatusCode.Should().Be(HttpStatusCode.OK);
res?.JWTToken.Should().NotBeNullOrEmpty();
successCount++;
}
else
{
i.Should().Be(6);
rsp.StatusCode.Should().Be(HttpStatusCode.TooManyRequests);
}
}
successCount.Should().Be(5);
}
[Fact]
public async Task AdminLoginV2()
{
var (resp, result) = await GuestClient.GETAsync<
Admin.Login.Endpoint_V2,
EmptyRequest,
int>(new());
resp?.StatusCode.Should().Be(HttpStatusCode.OK);
result.Should().Be(2);

as well as swagger snapshot tests such as these:

[Fact]
public async Task initial_release_doc_produces_correct_output()
{
var generator = serviceProvider.GetRequiredService<IOpenApiDocumentGenerator>();
var doc = await generator.GenerateAsync("Initial Release");
var json = doc.ToJson();
var currentDoc = JToken.Parse(json);
//await File.WriteAllTextAsync("initial-release.json", json);
var snapshot = File.ReadAllText("initial-release.json");
var snapshotDoc = JToken.Parse(snapshot);
currentDoc.Should().BeEquivalentTo(snapshotDoc);
}
[Fact]
public async Task release_1_doc_produces_correct_output()
{
var generator = serviceProvider.GetRequiredService<IOpenApiDocumentGenerator>();
var doc = await generator.GenerateAsync("Release 1.0");
var json = doc.ToJson();
var currentDoc = JToken.Parse(json);
//await File.WriteAllTextAsync("release-1.json", json);
var snapshot = File.ReadAllText("release-1.json");
var snapshotDoc = JToken.Parse(snapshot);
currentDoc.Should().BeEquivalentTo(snapshotDoc);
}
[Fact]
public async Task release_2_doc_produces_correct_output()
{
var generator = serviceProvider.GetRequiredService<IOpenApiDocumentGenerator>();
var doc = await generator.GenerateAsync("Release 2.0");
var json = doc.ToJson();
var currentDoc = JToken.Parse(json);
//await File.WriteAllTextAsync("release-2.json", json);
var snapshot = File.ReadAllText("release-2.json");
var snapshotDoc = JToken.Parse(snapshot);
currentDoc.Should().BeEquivalentTo(snapshotDoc);
}

if someone has the time, a more comprehensive test suite would be welcome 😉

@dj-nitehawk
Copy link
Member

dj-nitehawk commented Apr 25, 2023

okay... i have some progress...
upgrade FE packages to v5.10 and install FastEndpoints.AspVersioning package also.
then test out the following:

using Asp.Versioning;
using Asp.Versioning.Conventions;
using FastEndpoints;
using FastEndpoints.AspVersioning;
using FastEndpoints.Swagger;

VersionSets.CreateApi(">>Orders<<", v => v
    .HasApiVersion(1.0)
    .HasApiVersion(2.0));

VersionSets.CreateApi(">>Inventory<<", v =>
{
    v.HasApiVersion(1.0);
    v.HasApiVersion(1.1);
});

var builder = WebApplication.CreateBuilder();
builder.Services
    .AddFastEndpoints()
    .AddVersioning(o =>
    {
        o.DefaultApiVersion = new(1.0);
        o.AssumeDefaultVersionWhenUnspecified = true;
        o.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version");
    })
    .SwaggerDocument(o =>
    {
        o.DocumentSettings = x =>
        {
            x.DocumentName = "version one";
            x.ApiVersion(new(1.0));
        };
        o.AutoTagPathSegmentIndex = 0;
    })
    .SwaggerDocument(o =>
    {
        o.DocumentSettings = x =>
        {
            x.DocumentName = "version one point one";
            x.ApiVersion(new(1.1));
        };
        o.AutoTagPathSegmentIndex = 0;
    })
    .SwaggerDocument(o =>
    {
        o.DocumentSettings = x =>
        {
            x.DocumentName = "version two";
            x.ApiVersion(new(2.0));
        };
        o.AutoTagPathSegmentIndex = 0;
    });

var app = builder.Build();
app.UseAuthorization()
   .UseFastEndpoints()
   .UseSwaggerGen();

app.Run();

public class GetInvoices_v1 : EndpointWithoutRequest
{
    public override void Configure()
    {
        Get("invoices");
        AllowAnonymous();
        Options(x => x
            .WithVersionSet(">>Orders<<")
            .MapToApiVersion(1.0));
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await SendAsync("v1 - orders");
    }
}

public class GetInvoices_v2 : EndpointWithoutRequest
{
    public override void Configure()
    {
        Get("invoices");
        AllowAnonymous();
        Options(x => x
            .WithVersionSet(">>Orders<<")
            .MapToApiVersion(2.0));
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await SendAsync("v2 - orders");
    }
}

public class GetStockItems_v1 : EndpointWithoutRequest
{
    public override void Configure()
    {
        Get("stock-items");
        AllowAnonymous();
        Options(x => x
            .WithVersionSet(">>Inventory<<")
            .MapToApiVersion(1.0));
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await SendAsync("v1 - inventory");
    }
}

public class GetStockItems_v1_1 : EndpointWithoutRequest
{
    public override void Configure()
    {
        Get("stock-items");
        AllowAnonymous();
        Options(x => x
            .WithVersionSet(">>Inventory<<")
            .MapToApiVersion(1.1));
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await SendAsync("v1.1 - inventory");
    }
}

@zfchai

This comment was marked as off-topic.

@dj-nitehawk

This comment was marked as off-topic.

@zfchai

This comment was marked as off-topic.

@dj-nitehawk

This comment was marked as off-topic.

@zfchai

This comment was marked as off-topic.

@FastEndpoints FastEndpoints deleted a comment from zfchai Apr 26, 2023
@dj-nitehawk dj-nitehawk added implemented requested feature has been implemented and removed wip work is in progress labels Jul 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request implemented requested feature has been implemented
Development

No branches or pull requests

5 participants