.Net core versioning: Folder structure / namespaces
Asked Answered
B

2

7

I'm trying to figuring out versioning in .Net core Web Api 2.0 and I have some questions after seeing a lot of 'tutorials'.

For example I have a large api with a lot of controllers/models/etc.

1. What is the best way to create a new version?

  • I have seen people just putting all controllers in a different folder /controllers/v1/ / controllers/v2/, etc and the models also in the /models/v1/, models/v2, etc.
  • I have seen putting all controller versions in the same file and use attributes to specify which controller belongs to which version. (To me this looks messy because you loose track of which have multiple version and which dont).
  • I have seen people just copy pasting almost everything in new versioning folders: /v1/controllers, /v1/models, /v2/controllers, /v2/models. Which in essence is just cloning the whole code base to a new folder. (I like this one because if an older version can be deleted, you can just delete the whole folder and you're done).

2. How do you handle the namespace changes?

So for example you have a folder with v1 and it it all controllers, models, etc. And then you want to copy everything to a v2 for a new version. All namespaces in all those files do still have the .v1 in it. How do you rename all of them to a new namespace?

Berthaberthe answered 22/6, 2020 at 12:41 Comment(0)
C
4

I have seen almost all of the above mentioned approaches can work well. But as always it depends on a lot of factors. For instance:

  • Is it even possible (in your domain) to stop supporting previous versions after awhile?
  • Do you have influence on your consumers? I mean can you force them to upgrade?
  • Can you migrate old data to new data (on-demand or by separate migration steps)
  • Can you reroute old API consumers to new APIs?
  • etc.

These sort of questions can help you to identify which option would be preferable.

For instance if previous versions can't be deprecated because the external consumers of your API are already under maintenance and there is no easy way to migrate their data and reroute their requests then the file level separation would be a better fit for you. It is just matter of taste that you do it on the whole API level (v1/controller) or concept levels (controller/v1). I personally prefer the former because that gives a bit more flexibility in code organization. (it can evolve from version to version)

Cytherea answered 22/6, 2020 at 15:48 Comment(0)
G
0

Yes it is possible to implement global convetions using .NET Core:

    public static IServiceCollection AddApiVersioningSetup(this IServiceCollection services)
    {
        services.AddApiVersioning(options =>
        {
            options.DefaultApiVersion = new ApiVersion(1, 0);
            options.ReportApiVersions = true;
            options.AssumeDefaultVersionWhenUnspecified = true;
            options.ApiVersionReader = ApiVersionReader.Combine(
                new UrlSegmentApiVersionReader(),
                new HeaderApiVersionReader("x-api-version"));
            options.Conventions.Add(new GlobalVersionConvention(options.DefaultApiVersion));
        })
        .AddVersionedApiExplorer(options =>
        {
            options.GroupNameFormat = "'v'VVV";
            options.SubstituteApiVersionInUrl = true;
        });
        return services;
    }

You must also implement the GlobalVersionConvetion class so by default the version is setted in v1 if you wanna use another different version you can use Api.v2.Controllers.UserController. Here is the implementation:

public class GlobalVersionConvention : IControllerConvention
{
    private readonly ApiVersion _defaultVersion;

    public GlobalVersionConvention(ApiVersion defaultVersion)
    {
        _defaultVersion = defaultVersion;
    }

    public bool Apply(IControllerConventionBuilder builder, ControllerModel controller)
    {
        if (controller.ControllerType.Namespace == null)
        {
            builder.HasApiVersion(_defaultVersion);
            return true;
        }

        var ns = controller.ControllerType.Namespace.ToLower();

        if (ns.Contains(".v1"))
        {
            builder.HasApiVersion(new ApiVersion(1, 0));
        }
        else if (ns.Contains(".v2"))
        {
            builder.HasApiVersion(new ApiVersion(2, 0));
        }
        else if (ns.Contains(".v3"))
        {
            builder.HasApiVersion(new ApiVersion(3, 0));
        }
        else
        {
            builder.HasApiVersion(_defaultVersion);
        }

        return true;
    }
}
Guideline answered 7/10 at 19:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.