From c71cd6580ac12ac670a5553110bc6589782dcf48 Mon Sep 17 00:00:00 2001 From: rabdulatif Date: Sat, 5 Oct 2024 21:20:11 +0500 Subject: [PATCH 1/3] Implement AddServiceNamePrefixToPaths method to prefix Swagger paths with service name for Consul and PollConsul types --- .../Middleware/SwaggerForOcelotMiddleware.cs | 4 ++ .../Transformation/ISwaggerJsonTransformer.cs | 13 ++++++ .../SwaggerJsonTransformer.Consul.cs | 40 +++++++++++++++++++ .../Transformation/SwaggerJsonTransformer.cs | 2 +- .../SwaggerForOcelotMiddlewareShould.cs | 4 ++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs diff --git a/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs b/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs index d15c279..a054236 100644 --- a/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs +++ b/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs @@ -101,6 +101,10 @@ public async Task Invoke(HttpContext context, content = _transformer.Transform(content, routeOptions, GetServerName(context, endPoint), endPoint); } } + else + { + content = _transformer.AddServiceNamePrefixToPaths(content, endPoint, version); + } content = await ReconfigureUpstreamSwagger(context, content); diff --git a/src/MMLib.SwaggerForOcelot/Transformation/ISwaggerJsonTransformer.cs b/src/MMLib.SwaggerForOcelot/Transformation/ISwaggerJsonTransformer.cs index be875d0..00d4dc7 100644 --- a/src/MMLib.SwaggerForOcelot/Transformation/ISwaggerJsonTransformer.cs +++ b/src/MMLib.SwaggerForOcelot/Transformation/ISwaggerJsonTransformer.cs @@ -22,5 +22,18 @@ string Transform(string swaggerJson, IEnumerable routes, string serverOverride, SwaggerEndPointOptions endPointOptions); + + /// + /// Modifies the paths in a given Swagger JSON by adding a specified service name as a prefix to each path. + /// If the "paths" section is missing or null, the method returns the original Swagger JSON without modifications. + /// + /// The original Swagger JSON as a string. + /// The service name to be prefixed to each path in the Swagger JSON. + /// + /// + /// A modified Swagger JSON string where each path in the "paths" section is prefixed with the provided service name. + /// If the "paths" section does not exist or is null, the original Swagger JSON is returned. + /// + string AddServiceNamePrefixToPaths(string swaggerJson, SwaggerEndPointOptions serviceName, string version); } } diff --git a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs new file mode 100644 index 0000000..4f4a00e --- /dev/null +++ b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs @@ -0,0 +1,40 @@ +using MMLib.SwaggerForOcelot.Configuration; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; + +namespace MMLib.SwaggerForOcelot.Transformation; + +public partial class SwaggerJsonTransformer +{ + public string AddServiceNamePrefixToPaths(string swaggerJson, SwaggerEndPointOptions endPoint, string version) + { + SwaggerEndPointConfig config = + string.IsNullOrEmpty(version) + ? endPoint.Config.FirstOrDefault() + : endPoint.Config.FirstOrDefault(x => x.Version == version); + + var serviceName = config?.Service?.Name; + if (string.IsNullOrEmpty(serviceName)) + return swaggerJson; + + var swaggerDoc = JsonSerializer.Deserialize>(swaggerJson); + + if (swaggerDoc != null && swaggerDoc.ContainsKey("paths")) + { + var paths = JsonSerializer.Deserialize>(swaggerDoc["paths"].ToString()); + var modifiedPaths = new Dictionary(); + + foreach (var path in paths) + { + var newPath = $"/{serviceName}{path.Key}"; + modifiedPaths[newPath] = path.Value; + } + + swaggerDoc["paths"] = modifiedPaths; + return JsonSerializer.Serialize(swaggerDoc, new JsonSerializerOptions { WriteIndented = true }); + } + + return swaggerJson; + } +} diff --git a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs index c4db880..9033b44 100644 --- a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs +++ b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs @@ -15,7 +15,7 @@ namespace MMLib.SwaggerForOcelot.Transformation /// Class which implement transformation downstream service swagger json into upstream format /// /// - public class SwaggerJsonTransformer : ISwaggerJsonTransformer + public partial class SwaggerJsonTransformer : ISwaggerJsonTransformer { private readonly OcelotSwaggerGenOptions _ocelotSwaggerGenOptions; private readonly IMemoryCache _memoryCache; diff --git a/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs b/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs index a8b4d33..a1c2018 100644 --- a/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs +++ b/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs @@ -494,6 +494,10 @@ public string Transform(string swaggerJson, { return _transformedJson; } + + public string AddServiceNamePrefixToPaths(string swaggerJson, + SwaggerEndPointOptions serviceName, + string version) => _transformedJson; } } } From b3d41e66d5b05fc1d8bca5e09c3dac9b7a2bd154 Mon Sep 17 00:00:00 2001 From: rabdulatif Date: Sun, 6 Oct 2024 17:44:37 +0500 Subject: [PATCH 2/3] Add service name prefixing logic to Swagger paths in SwaggerForOcelotMiddleware --- .../Middleware/SwaggerForOcelotMiddleware.cs | 1 + .../SwaggerJsonTransformer.Consul.cs | 60 +++++++++++++------ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs b/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs index a054236..095208f 100644 --- a/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs +++ b/src/MMLib.SwaggerForOcelot/Middleware/SwaggerForOcelotMiddleware.cs @@ -104,6 +104,7 @@ public async Task Invoke(HttpContext context, else { content = _transformer.AddServiceNamePrefixToPaths(content, endPoint, version); + } content = await ReconfigureUpstreamSwagger(context, content); diff --git a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs index 4f4a00e..f0d6b2a 100644 --- a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs +++ b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs @@ -1,40 +1,62 @@ using MMLib.SwaggerForOcelot.Configuration; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.Linq; -using System.Text.Json; namespace MMLib.SwaggerForOcelot.Transformation; +/// +/// +/// public partial class SwaggerJsonTransformer { + /// + /// Modifies the paths in a given Swagger JSON by adding a specified service name as a prefix to each path. + /// If the "paths" section is missing or null, the method returns the original Swagger JSON without modifications. + /// + /// The original Swagger JSON as a string. + /// The service name to be prefixed to each path in the Swagger JSON. + /// + /// + /// A modified Swagger JSON string where each path in the "paths" section is prefixed with the provided service name. + /// If the "paths" section does not exist or is null, the original Swagger JSON is returned. + /// public string AddServiceNamePrefixToPaths(string swaggerJson, SwaggerEndPointOptions endPoint, string version) { - SwaggerEndPointConfig config = - string.IsNullOrEmpty(version) - ? endPoint.Config.FirstOrDefault() - : endPoint.Config.FirstOrDefault(x => x.Version == version); + var config = string.IsNullOrEmpty(version) + ? endPoint.Config.FirstOrDefault() + : endPoint.Config.FirstOrDefault(x => x.Version == version); var serviceName = config?.Service?.Name; if (string.IsNullOrEmpty(serviceName)) return swaggerJson; - var swaggerDoc = JsonSerializer.Deserialize>(swaggerJson); + var swaggerObj = JObject.Parse(swaggerJson); + if (!swaggerObj.TryGetValue(OpenApiProperties.Paths, out var swaggerPaths)) + return swaggerJson; - if (swaggerDoc != null && swaggerDoc.ContainsKey("paths")) - { - var paths = JsonSerializer.Deserialize>(swaggerDoc["paths"].ToString()); - var modifiedPaths = new Dictionary(); + if (swaggerPaths is not JObject pathsObj) + return swaggerJson; - foreach (var path in paths) - { - var newPath = $"/{serviceName}{path.Key}"; - modifiedPaths[newPath] = path.Value; - } + var properties = pathsObj.Properties().ToList(); + properties.ForEach(f => SetToPathServiceName(f, pathsObj, serviceName)); - swaggerDoc["paths"] = modifiedPaths; - return JsonSerializer.Serialize(swaggerDoc, new JsonSerializerOptions { WriteIndented = true }); - } + return swaggerObj.ToString(); + } + + /// + /// + /// + /// + /// + /// + private void SetToPathServiceName(JProperty jProperty, JObject pathsObj, string serviceName) + { + jProperty.Remove(); - return swaggerJson; + var path = $"/{serviceName}{jProperty.Name}"; + pathsObj.Add(path, jProperty.Value); } } From 94867321bb6946b7149cad3f1a4f230e49f5e12e Mon Sep 17 00:00:00 2001 From: rabdulatif Date: Sun, 6 Oct 2024 18:15:52 +0500 Subject: [PATCH 3/3] Added TryParse method to parse json safely --- .../Extensions/JsonExtensions.cs | 30 +++++++++++++++++++ .../SwaggerJsonTransformer.Consul.cs | 5 +++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/MMLib.SwaggerForOcelot/Extensions/JsonExtensions.cs diff --git a/src/MMLib.SwaggerForOcelot/Extensions/JsonExtensions.cs b/src/MMLib.SwaggerForOcelot/Extensions/JsonExtensions.cs new file mode 100644 index 0000000..f56c288 --- /dev/null +++ b/src/MMLib.SwaggerForOcelot/Extensions/JsonExtensions.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json.Linq; +using System; + +namespace MMLib.SwaggerForOcelot.Extensions; + +/// +/// +/// +public static class JsonExtensions +{ + /// + /// + /// + /// + /// + /// + public static bool TryParse(this string swaggerJson, out JObject jObj) + { + try + { + jObj = JObject.Parse(swaggerJson); + return true; + } + catch (Exception ex) + { + jObj = null; + return false; + } + } +} diff --git a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs index f0d6b2a..d7533ba 100644 --- a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs +++ b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.Consul.cs @@ -1,4 +1,5 @@ using MMLib.SwaggerForOcelot.Configuration; +using MMLib.SwaggerForOcelot.Extensions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -33,7 +34,9 @@ public string AddServiceNamePrefixToPaths(string swaggerJson, SwaggerEndPointOpt if (string.IsNullOrEmpty(serviceName)) return swaggerJson; - var swaggerObj = JObject.Parse(swaggerJson); + if (!swaggerJson.TryParse(out var swaggerObj)) + return swaggerJson; + if (!swaggerObj.TryGetValue(OpenApiProperties.Paths, out var swaggerPaths)) return swaggerJson;