From c0576099ae2df6779442b1a9155539b4f4e9fcae Mon Sep 17 00:00:00 2001 From: catcherwong Date: Sat, 8 Jul 2023 02:46:53 +0000 Subject: [PATCH] Add an OpenAPI definition (#484) --- ...Cloud5mins.ShortenerTools.Functions.csproj | 7 ++-- .../Functions/UrlArchive.cs | 6 +++ .../Functions/UrlClickStatsByDay.cs | 6 +++ .../Functions/UrlCreate.cs | 13 +++++-- .../Functions/UrlList.cs | 4 ++ .../Functions/UrlRedirect.cs | 4 ++ .../Functions/UrlUpdate.cs | 6 +++ .../Program.cs | 37 +++++++++++++++++++ 8 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/Cloud5mins.ShortenerTools.Functions/Cloud5mins.ShortenerTools.Functions.csproj b/src/Cloud5mins.ShortenerTools.Functions/Cloud5mins.ShortenerTools.Functions.csproj index 982a1b53c..8b67480fb 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Cloud5mins.ShortenerTools.Functions.csproj +++ b/src/Cloud5mins.ShortenerTools.Functions/Cloud5mins.ShortenerTools.Functions.csproj @@ -7,9 +7,10 @@ - - - + + + + diff --git a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlArchive.cs b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlArchive.cs index 0e35338af..0dc628900 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlArchive.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlArchive.cs @@ -28,6 +28,7 @@ using Cloud5mins.ShortenerTools.Core.Domain; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; using Microsoft.Extensions.Logging; using System; using System.IO; @@ -51,6 +52,11 @@ public UrlArchive(ILoggerFactory loggerFactory, ShortenerSettings settings) } [Function("UrlArchive")] + [OpenApiOperation(operationId: "UrlArchive", tags: new[] { "Url" }, Summary = "Archive a short url")] + [OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ShortUrlEntity), Description = "Short url that needs to be archived.")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ShortUrlEntity), Description = "The OK response")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(string), Description = "Unexpected error")] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NotFound, Description = "Invalid inputs")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "api/UrlArchive")] HttpRequestData req, ExecutionContext context) diff --git a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlClickStatsByDay.cs b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlClickStatsByDay.cs index e64299e56..f672142f1 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlClickStatsByDay.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlClickStatsByDay.cs @@ -27,6 +27,7 @@ using Google.Protobuf.WellKnownTypes; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; using Microsoft.Extensions.Logging; using System; using System.IO; @@ -50,6 +51,11 @@ public UrlClickStatsByDay(ILoggerFactory loggerFactory, ShortenerSettings settin } [Function("UrlClickStatsByDay")] + [OpenApiOperation(operationId: "UrlClickStatsByDay", tags: new[] { "Url" }, Summary = "Get url click stats by day")] + [OpenApiRequestBody(contentType: "application/json", bodyType: typeof(UrlClickStatsRequest), Description = "The stats request")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ClickDateList), Description = "The OK response")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(string), Description = "Unexpected error")] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NotFound, Description = "Invalid inputs")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "api/UrlClickStatsByDay")] HttpRequestData req, ExecutionContext context) diff --git a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlCreate.cs b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlCreate.cs index 80373f9de..cabcbc4c6 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlCreate.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlCreate.cs @@ -24,6 +24,7 @@ using Cloud5mins.ShortenerTools.Core.Messages; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; using Microsoft.Extensions.Logging; using System; using System.IO; @@ -47,8 +48,14 @@ public UrlCreate(ILoggerFactory loggerFactory, ShortenerSettings settings) } [Function("UrlCreate")] + [OpenApiOperation(operationId: "UrlCreate", tags: new[] { "Url" }, Summary = "Create a new short url")] + [OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ShortRequest), Description = "Short url that needs to be added.")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ShortResponse), Description = "The OK response")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(string))] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.Conflict, contentType: "application/json", bodyType: typeof(string), Description = "Short uRL already exist")] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NotFound, Description = "Invalid inputs")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "api/UrlCreate")] HttpRequestData req, + [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "api/UrlCreate")] HttpRequestData req, ExecutionContext context ) { @@ -126,8 +133,8 @@ ExecutionContext context { _logger.LogError(ex, "An unexpected error was encountered."); - var badResponse = req.CreateResponse(HttpStatusCode.BadRequest); - await badResponse.WriteAsJsonAsync(new { ex.Message }); + var badResponse = req.CreateResponse(); + await badResponse.WriteAsJsonAsync(new { ex.Message }, HttpStatusCode.BadRequest); return badResponse; } diff --git a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlList.cs b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlList.cs index 97c78e819..f47e33576 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlList.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlList.cs @@ -19,6 +19,7 @@ using Cloud5mins.ShortenerTools.Core.Messages; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; using Microsoft.Extensions.Logging; using System; using System.Linq; @@ -41,6 +42,9 @@ public UrlList(ILoggerFactory loggerFactory, ShortenerSettings settings) } [Function("UrlList")] + [OpenApiOperation(operationId: "UrlList", tags: new[] { "Url" }, Summary = "List short urls")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ListResponse), Description = "The OK response")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(string), Description = "Unexpected error")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "api/UrlList")] HttpRequestData req, ExecutionContext context) { diff --git a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlRedirect.cs b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlRedirect.cs index f73788817..0a65a6a96 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlRedirect.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlRedirect.cs @@ -1,6 +1,7 @@ using Cloud5mins.ShortenerTools.Core.Domain; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; using Microsoft.Extensions.Logging; using System.Net; using System.Threading; @@ -20,6 +21,9 @@ public UrlRedirect(ILoggerFactory loggerFactory, ShortenerSettings settings) } [Function("UrlRedirect")] + [OpenApiOperation(operationId: "UrlRedirect", tags: new[] { "Url" }, Summary = "Redirect to target url")] + [OpenApiParameter(name: "shortUrl", Description = "The short url")] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Redirect)] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "{shortUrl}")] HttpRequestData req, diff --git a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlUpdate.cs b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlUpdate.cs index 7d839e2c6..24c8b6b25 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlUpdate.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Functions/UrlUpdate.cs @@ -33,6 +33,7 @@ // using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; using Microsoft.Extensions.Logging; using System; using System.IO; @@ -55,6 +56,11 @@ public UrlUpdate(ILoggerFactory loggerFactory, ShortenerSettings settings) } [Function("UrlUpdate")] + [OpenApiOperation(operationId: "UrlUpdate", tags: new[] { "Url" }, Summary = "Update an existing short url")] + [OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ShortUrlEntity), Description = "JSON request body")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ShortUrlEntity), Description = "The OK response")] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(string))] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NotFound, Description = "Invalid inputs")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "api/UrlUpdate")] HttpRequestData req, ExecutionContext context diff --git a/src/Cloud5mins.ShortenerTools.Functions/Program.cs b/src/Cloud5mins.ShortenerTools.Functions/Program.cs index 067f42c65..2697c2691 100644 --- a/src/Cloud5mins.ShortenerTools.Functions/Program.cs +++ b/src/Cloud5mins.ShortenerTools.Functions/Program.cs @@ -1,7 +1,12 @@ using Cloud5mins.ShortenerTools.Core.Domain; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi.Models; +using System; namespace Cloud5mins.ShortenerTools { @@ -26,6 +31,38 @@ public static void Main() // Add our configuration class services.AddSingleton(options => { return shortenerSettings; }); + + // Add OpenAPI definition + services.AddSingleton(_ => + { + var options = new OpenApiConfigurationOptions() + { + Info = new OpenApiInfo() + { + Version = "1.0.0", + Title = "Azure Url Shortener", + Description = "Azure Url Shortener", + TermsOfService = new Uri("https://github.com/microsoft/AzUrlShortener"), + Contact = new OpenApiContact() + { + Name = "Contact the developer", + Url = new Uri("https://github.com/microsoft/AzUrlShortener/issues"), + }, + License = new OpenApiLicense() + { + Name = "MIT", + Url = new Uri("https://github.com/microsoft/AzUrlShortener/blob/main/LICENSE"), + } + }, + Servers = DefaultOpenApiConfigurationOptions.GetHostNames(), + OpenApiVersion = OpenApiVersionType.V2, + IncludeRequestingHostName = true, + ForceHttps = false, + ForceHttp = false, + }; + + return options; + }); }) .Build();