I'm developing a REST API using Azure Functions with .NET 5 (Isolated) and I want to add an OpenAPI spec for each route. But it looks like this:
namespace AzureFunctionsREST.API.Functions
{
public class ReporterFunction : BaseFunction
{
private readonly IReporterRepository _reporterRepository;
public ReporterFunction(IReporterRepository reporterRepository)
{
this._reporterRepository = reporterRepository;
}
[Function("ReporterList")]
[OpenApiOperation(tags: new[] { "reporter" }, Summary = "Retrieve all reporters")]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Reporter[]),
Description = "All reporters")]
public async Task<HttpResponseData> List([HttpTrigger(AuthorizationLevel.Function, "get", Route = "reporter")] HttpRequestData req,
FunctionContext executionContext)
{
// List reporters
}
[Function("ReporterGet")]
[OpenApiOperation(tags: new[] { "reporter" }, Summary = "Retrieve reporter")]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiParameter(name: "reporterId", In = ParameterLocation.Path, Required = true, Type = typeof(string))]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Reporter),
Description = "Reporter")]
public async Task<HttpResponseData> Get([HttpTrigger(AuthorizationLevel.Function, "get", Route = "reporter/{reporterId:required}")] HttpRequestData req,
FunctionContext executionContext)
{
// Get reporter
}
[Function("ReporterPost")]
[OpenApiOperation(tags: new[] { "reporter" }, Summary = "Create a new reporter")]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ReporterRequest))]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Reporter),
Description = "Created reporter")]
public async Task<HttpResponseData> Post([HttpTrigger(AuthorizationLevel.Function, "post", Route = "reporter")] HttpRequestData req,
FunctionContext executionContext)
{
// Create reporter
}
[Function("ReporterPut")]
[OpenApiOperation(tags: new[] { "reporter" }, Summary = "Update a reporter")]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiParameter(name: "reporterId", In = ParameterLocation.Path, Required = true, Type = typeof(string))]
[OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ReporterRequest))]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Reporter),
Description = "Updated reporter")]
public async Task<HttpResponseData> Put([HttpTrigger(AuthorizationLevel.Function, "put", Route = "reporter/{reporterId:required}")] HttpRequestData req,
FunctionContext executionContext)
{
// Update reporter
}
[Function("ReporterDelete")]
[OpenApiOperation(tags: new[] { "reporter" }, Summary = "Delete a reporter")]
[OpenApiParameter(name: "reporterId", In = ParameterLocation.Path, Required = true, Type = typeof(string))]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Reporter),
Description = "Deleted reporter")]
public async Task<HttpResponseData> Delete([HttpTrigger(AuthorizationLevel.Function, "delete", Route = "reporter/{reporterId:required}")] HttpRequestData req,
FunctionContext executionContext)
{
// Delete reporter
}
}
}
All five methods are just routes for simple CRUD operations. As you can see these lines are duplicated in every function (route):
[OpenApiOperation(tags: new[] { "reporter" }, Summary = "Retrieve all reporters")]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Reporter[]),
Description = "All reporters")]
I'm using a single class for interaction with each model (e.g. 10 models = 10 classes) so in each class:
- Tags will all be the same
- Security will be the same
- Response body will all be the same (except
[GET] /api/reporter
which will return as an array)
And also parameter name is also duplicated (see reporterId
):
[OpenApiParameter(name: "reporterId", In = ParameterLocation.Path, Required = true, Type = typeof(string))]
public async Task<HttpResponseData> Put([HttpTrigger(AuthorizationLevel.Function, "put", Route = "reporter/{reporterId:required}")] HttpRequestData req,
FunctionContext executionContext) { }
I've tried something like putting values in a variable and using it in the attributes (which is not possible). So, I'm wondering is there a way to refactor this so these lines won't get duplicated all over?
Additional Info:
- GitHub - https://github.com/phwt/azure-functions-rest/tree/feature/mongo
- The functions will be inside
AzureFunctionsREST.API/Functions
- This project is a PoC for REST API + OpenAPI + MongoDB + repository pattern on Azure Functions. So, there might be a lot of unrelated codes.
- The functions will be inside
- Related documentations on OpenAPI with Azure Functions
The updated version is available here