diff --git a/README.md b/README.md
index 58cc768..48f469d 100644
--- a/README.md
+++ b/README.md
@@ -570,6 +570,20 @@ services.AddSwaggerForOcelot(Configuration,
Note, this does not affect nor checks the swagger document's `securityDefinitions` property.
+## Downstream Documentation Caching
+If your downstream documentation is too large, the response time may be slow.
+To address this issue, you can enable caching of transformed documentation by setting the
+`DownstreamDocsCacheExpire` parameter. If this parameter is not provided, the documentation won't be cached.
+If there is any change in the downstream documentation, the cache will be refreshed.
+
+```csharp
+services.AddSwaggerForOcelot(Configuration,
+ setup =>
+ {
+ setup.DownstreamDocsCacheExpire = TimeSpan.FromMinutes(10);
+ });
+```
+
## Limitation
- Now, this library support only `{everything}` as a wildcard in routing definition. #68
diff --git a/src/MMLib.SwaggerForOcelot/Configuration/OcelotSwaggerGenOptions.cs b/src/MMLib.SwaggerForOcelot/Configuration/OcelotSwaggerGenOptions.cs
index abdd0ef..9625aab 100644
--- a/src/MMLib.SwaggerForOcelot/Configuration/OcelotSwaggerGenOptions.cs
+++ b/src/MMLib.SwaggerForOcelot/Configuration/OcelotSwaggerGenOptions.cs
@@ -26,6 +26,14 @@ public class OcelotSwaggerGenOptions
///
public bool GenerateDocsForGatewayItSelf { get; set; } = false;
+ ///
+ /// Gets or sets a value indicating downstream docs cache expire duration in seconds.
+ ///
+ ///
+ /// 0 if it won't be cached; otherwise, cache expire duration in seconds.
+ ///
+ public TimeSpan DownstreamDocsCacheExpire { get; set; } = TimeSpan.Zero;
+
///
/// Generates docs for gateway it self with options.
///
@@ -33,7 +41,7 @@ public class OcelotSwaggerGenOptions
public void GenerateDocsDocsForGatewayItSelf(Action options = null)
{
GenerateDocsForGatewayItSelf = true;
-
+
OcelotGatewayItSelfSwaggerGenOptions = new OcelotGatewayItSelfSwaggerGenOptions();
options?.Invoke(OcelotGatewayItSelfSwaggerGenOptions);
diff --git a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs
index 07750d4..7a5b8b1 100644
--- a/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs
+++ b/src/MMLib.SwaggerForOcelot/Transformation/SwaggerJsonTransformer.cs
@@ -1,10 +1,14 @@
-using Kros.IO;
+using Kros.IO;
+using Microsoft.Extensions.Caching.Memory;
using MMLib.SwaggerForOcelot.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
namespace MMLib.SwaggerForOcelot.Transformation
{
@@ -15,14 +19,37 @@ namespace MMLib.SwaggerForOcelot.Transformation
public class SwaggerJsonTransformer : ISwaggerJsonTransformer
{
private readonly OcelotSwaggerGenOptions _ocelotSwaggerGenOptions;
+ private readonly IMemoryCache _memoryCache;
- public SwaggerJsonTransformer(OcelotSwaggerGenOptions ocelotSwaggerGenOptions)
+ public SwaggerJsonTransformer(OcelotSwaggerGenOptions ocelotSwaggerGenOptions, IMemoryCache memoryCache)
{
_ocelotSwaggerGenOptions = ocelotSwaggerGenOptions;
+ _memoryCache = memoryCache;
}
///
- public string Transform(string swaggerJson,
+ public string Transform(
+ string swaggerJson,
+ IEnumerable routes,
+ string serverOverride,
+ SwaggerEndPointOptions endPointOptions)
+ {
+ if (_ocelotSwaggerGenOptions.DownstreamDocsCacheExpire == TimeSpan.Zero)
+ {
+ return TransformSwaggerOrOpenApi(swaggerJson, routes, serverOverride, endPointOptions);
+ }
+
+ return _memoryCache.GetOrCreate(
+ ComputeHash(swaggerJson),
+ entry =>
+ {
+ entry.AbsoluteExpirationRelativeToNow = _ocelotSwaggerGenOptions.DownstreamDocsCacheExpire;
+ return TransformSwaggerOrOpenApi(swaggerJson, routes, serverOverride, endPointOptions);
+ });
+ }
+
+ private string TransformSwaggerOrOpenApi(
+ string swaggerJson,
IEnumerable routes,
string serverOverride,
SwaggerEndPointOptions endPointOptions)
@@ -327,5 +354,13 @@ private static void TransformServerPaths(JObject openApi, string serverOverride,
}
}
}
+
+ private static string ComputeHash(string input)
+ {
+ using var sha256 = SHA256.Create();
+ byte[] bytes = Encoding.UTF8.GetBytes(input);
+ byte[] hash = sha256.ComputeHash(bytes);
+ return Convert.ToBase64String(hash);
+ }
}
}
diff --git a/tests/MMLib.SwaggerForOcelot.BenchmarkTests/SwaggerJsonTransfromerBenchmark.cs b/tests/MMLib.SwaggerForOcelot.BenchmarkTests/SwaggerJsonTransfromerBenchmark.cs
index 56cfe9f..1ce5bd5 100644
--- a/tests/MMLib.SwaggerForOcelot.BenchmarkTests/SwaggerJsonTransfromerBenchmark.cs
+++ b/tests/MMLib.SwaggerForOcelot.BenchmarkTests/SwaggerJsonTransfromerBenchmark.cs
@@ -1,4 +1,6 @@
using BenchmarkDotNet.Attributes;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Options;
using MMLib.SwaggerForOcelot.Configuration;
using MMLib.SwaggerForOcelot.Transformation;
using System.Collections.Generic;
@@ -14,6 +16,7 @@ public class SwaggerJsonTransfromerBenchmark
private readonly string _swagger;
private readonly SwaggerJsonTransformer _transformer;
private readonly List _routeOptions;
+ private readonly IMemoryCache memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
public SwaggerJsonTransfromerBenchmark()
{
@@ -40,7 +43,7 @@ public SwaggerJsonTransfromerBenchmark()
}
};
- _transformer = new SwaggerJsonTransformer(new OcelotSwaggerGenOptions());
+ _transformer = new SwaggerJsonTransformer(new OcelotSwaggerGenOptions(), memoryCache);
}
[Benchmark]
diff --git a/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs b/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs
index 4f6f161..bd112a6 100644
--- a/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs
+++ b/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotMiddlewareShould.cs
@@ -10,6 +10,7 @@
using JsonDiffPatchDotNet;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using MMLib.SwaggerForOcelot.Configuration;
using MMLib.SwaggerForOcelot.Middleware;
@@ -23,6 +24,7 @@
using Swashbuckle.AspNetCore.Swagger;
using Xunit;
using Xunit.Sdk;
+using Options = Microsoft.Extensions.Options.Options;
namespace MMLib.SwaggerForOcelot.Tests
{
@@ -35,6 +37,7 @@ public async Task AllowVersionPlaceholder()
const string version = "v1";
const string key = "projects";
HttpContext httpContext = GetHttpContext(requestPath: $"/{version}/{key}");
+ IMemoryCache memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
var next = new TestRequestDelegate();
@@ -82,7 +85,7 @@ public async Task AllowVersionPlaceholder()
string swaggerJson,
IEnumerable routeOptions,
string serverOverride,
- SwaggerEndPointOptions options) => new SwaggerJsonTransformer(OcelotSwaggerGenOptions.Default)
+ SwaggerEndPointOptions options) => new SwaggerJsonTransformer(OcelotSwaggerGenOptions.Default, memoryCache)
.Transform(swaggerJson, routeOptions, serverOverride, options));
var swaggerForOcelotMiddleware = new SwaggerForOcelotMiddleware(
next.Invoke,
@@ -167,6 +170,7 @@ public async Task RespectDownstreamHttpVersionRouteSetting()
const string version = "v1";
const string key = "projects";
HttpContext httpContext = GetHttpContext(requestPath: $"/{version}/{key}");
+ IMemoryCache memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
var next = new TestRequestDelegate();
@@ -200,7 +204,7 @@ public async Task RespectDownstreamHttpVersionRouteSetting()
string swaggerJson,
IEnumerable routeOptions,
string serverOverride,
- SwaggerEndPointOptions options) => new SwaggerJsonTransformer(OcelotSwaggerGenOptions.Default)
+ SwaggerEndPointOptions options) => new SwaggerJsonTransformer(OcelotSwaggerGenOptions.Default, memoryCache)
.Transform(swaggerJson, routeOptions, serverOverride, options));
var swaggerForOcelotMiddleware = new SwaggerForOcelotMiddleware(
next.Invoke,
diff --git a/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotShould.cs b/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotShould.cs
index 1ee7b80..27b898a 100644
--- a/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotShould.cs
+++ b/tests/MMLib.SwaggerForOcelot.Tests/SwaggerForOcelotShould.cs
@@ -1,4 +1,5 @@
using JsonDiffPatchDotNet;
+using Microsoft.Extensions.Caching.Memory;
using MMLib.SwaggerForOcelot.Configuration;
using MMLib.SwaggerForOcelot.Transformation;
using Newtonsoft.Json.Linq;
@@ -19,13 +20,14 @@ public class SwaggerForOcelotShould
public void TransferDownstreamSwaggerToUpstreamFormat(TestCase testData)
{
var options = new OcelotSwaggerGenOptions();
+ IMemoryCache memoryCache = new MemoryCache(Microsoft.Extensions.Options.Options.Create(new MemoryCacheOptions()));
foreach ((string key, string value) in testData.AuthenticationProviderKeyMap)
{
options.AuthenticationProviderKeyMap.Add(key, value);
}
- var transformer = new SwaggerJsonTransformer(options);
+ var transformer = new SwaggerJsonTransformer(options, memoryCache);
string transformed = transformer.Transform(
testData.DownstreamSwagger.ToString(),
@@ -33,8 +35,7 @@ public void TransferDownstreamSwaggerToUpstreamFormat(TestCase testData)
testData.HostOverride,
new SwaggerEndPointOptions()
{
- TakeServersFromDownstreamService = testData.TakeServersFromDownstreamService,
- RemoveUnusedComponentsFromScheme = testData.RemoveUnusedComponentsFromScheme
+ TakeServersFromDownstreamService = testData.TakeServersFromDownstreamService, RemoveUnusedComponentsFromScheme = testData.RemoveUnusedComponentsFromScheme
});
AreEqual(transformed, testData.ExpectedTransformedSwagger, testData.FileName);