I’m currently building an ASP.NET Core API used to convert between document formats. You can upload a document, specify the from and to format and get a converted document back.
[HttpPost] | |
public IActionResult Convert(string from, string to, Uri file) | |
{ | |
var converter = new DocumentConverter(); | |
if (!file.IsFile) | |
throw new InvalidOperationException(); | |
string filename = System.IO.Path.GetFileName(file.LocalPath); | |
var stream = converter.ConvertDocument(file, to); | |
var fileProvider = new FileExtensionContentTypeProvider(); | |
// Figures out what the content type should be based on the file name. | |
if (!fileProvider.TryGetContentType(to, out string contentType)) | |
{ | |
throw new ArgumentOutOfRangeException($"Unable to find Content Type for file type {to}."); | |
} | |
return File(stream, contentType); | |
} |
The list of supported conversions is dynamically determined based on a list of format providers loaded through a plugin architecture.
To help developers in getting to know the API, I created Open API documentation using Swagger. Unfortunately the generated Open API documentation wasn’t that useful out-of-the-box as you get no hint on the possible “from” and “to” values.
My first idea would be to change the string value to an enum but this would require a recompile every time a new document format is introduced(and make my plugin architecture obsolete). My second idea was to just update the documentation, but in fact this was even worse than my first idea.
Time to find a better solution: I created a custom ParameterFilter that dynamically generates a list of available values based on the loaded plugins.
Here is the ParameterFilter:
public class FileExtensionsParameterFilter | |
: IParameterFilter | |
{ | |
public void Apply(OpenApiParameter parameter, ParameterFilterContext context) | |
{ | |
if (parameter.Name.Equals("from", StringComparison.InvariantCultureIgnoreCase)) | |
{ | |
var converter = new DocumentConverter(); | |
parameter.Schema.Enum = converter.SupportedFileExtensions.Select(f => new OpenApiString(f)).ToList<IOpenApiAny>(); | |
} | |
} | |
} |
And here is the updated Swagger registration:
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddControllers(); | |
services.AddSwaggerGen(c => | |
{ | |
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Document Conversion API", Version = "v1" }); | |
c.ParameterFilter<FileExtensionsParameterFilter>(); | |
}); | |
} |
My Open API documentation now looks like this: