So, I'm being forced into creating a gateway by the fact that an API I want to consume in my Blazor WASM app doesn't play nicely with CORS.
So I want to create the quickest, laziest gateway API I can. This is categorically not going to be used for production code so I don't care about security or anything of the sort.
The shortest I've been able to come up with so far is:
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "cors",
policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
});
});
var app = builder.Build();
app.UseCors("cors");
app.MapGet("/discos-proxy/{*discosRoute}", async (string discosRoute, HttpContext context) =>
{
HttpClient client = new();
client.BaseAddress = new(app.Configuration.GetSection("DiscosOptions:DiscosApiUrl").Value);
Console.WriteLine(context.Request.Headers.Authorization);
client.DefaultRequestHeaders.Authorization = new("bearer", context.Request.Headers.Authorization.ToString().Split(' ')[1]);
HttpResponseMessage res = await client.GetAsync(discosRoute);
res.EnsureSuccessStatusCode();
Stream contentStream = await res.Content.ReadAsStreamAsync();
using StreamReader reader = new(contentStream);
string content = await reader.ReadToEndAsync();
return content;
});
app.Run();
I tried returning just the HttpResponseMessage
directly but that doesn't seem to pull the content through.
So there are some obvious issues with this:
So am I missing a trick here or is there really no simple way to just proxy a request using these minimal APIs?
It seems as though the suggestion from @CodingMytra in the comments was the easiest solution.
To create this gateway with ocelot I need to install the Ocelot
package from Nuget and then have the following in my Program.cs
.
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Configuration
.AddJsonFile("appsettings.json")
.AddJsonFile("ocelot.json")
.AddEnvironmentVariables();
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
builder.Services.AddOcelot();
WebApplication app = builder.Build();
app.UseCors("CorsPolicy");
await app.UseOcelot();
await app.RunAsync();
It goes without saying that the very free CORS policy in this example should be tightened to suit your use case.
Essentially, I've just added CORS options (with .UseCors(...)
and .AddCors(...)
), and Ocelot options (with .AddOcelot()
and .UseOcelot()
).
Then, in my ocelot.json
:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "discosweb.esoc.esa.int",
"Port": 443
}
],
"UpstreamPathTemplate": "/{everything}",
"UpstreamHttpMethod": [ "Get" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:5002/"
}
}
This configuration takes every get request sent to the gateway and reroutes it to the downstream host (and prepends /api/
to the path).