Skip to content

Commit

Permalink
Merge pull request #336 from microsoft/generalise-query-parameters
Browse files Browse the repository at this point in the history
generalise query parameter processing
  • Loading branch information
gloveboxes authored Aug 10, 2024
2 parents a750d7d + fab3350 commit 21fc935
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 22 deletions.
13 changes: 7 additions & 6 deletions src/AzureAIProxy/Routes/AzureAISearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public static RouteGroupBuilder MapAzureAISearchRoutes(this RouteGroupBuilder bu
private static async Task<IResult> ProcessRequestAsync(
[FromServices] ICatalogService catalogService,
[FromServices] IProxyService proxyService,
[FromQuery(Name = "api-version")] string apiVersion,
[FromBody] JsonDocument requestJsonDoc,
HttpContext context,
string index
Expand All @@ -46,10 +45,11 @@ string index
$"Deployment '{index}' not found for this event. Available deployments are: {string.Join(", ", eventCatalog.Select(d => d.DeploymentName))}"
);

var url = GenerateEndpointUrl(deployment, extPath, apiVersion);
var url = GenerateEndpointUrl(deployment, extPath);
var (responseContent, statusCode) = await proxyService.HttpPostAsync(
url,
deployment.EndpointKey,
context,
requestJsonDoc,
requestContext,
deployment
Expand All @@ -58,10 +58,8 @@ string index
}
}

private static Uri GenerateEndpointUrl(Deployment deployment, string extPath, string apiVersion)
private static UriBuilder GenerateEndpointUrl(Deployment deployment, string extPath)
{
var baseUrl = deployment.EndpointUrl.TrimEnd('/');

string path = extPath switch
{
"/{index}/docs/search" => $"/indexes/{deployment.DeploymentName.Trim()}/docs/search",
Expand All @@ -70,6 +68,9 @@ private static Uri GenerateEndpointUrl(Deployment deployment, string extPath, st
_ => throw new ArgumentException("Invalid route pattern"),
};

return new Uri($"{baseUrl}{path}?api-version={apiVersion}");
return new UriBuilder(deployment.EndpointUrl.TrimEnd('/'))
{
Path = path
};
}
}
13 changes: 7 additions & 6 deletions src/AzureAIProxy/Routes/AzureOpenAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public static RouteGroupBuilder MapAzureOpenAIRoutes(this RouteGroupBuilder buil
private static async Task<IResult> ProcessRequestAsync(
[FromServices] ICatalogService catalogService,
[FromServices] IProxyService proxyService,
[FromQuery(Name = "api-version")] string apiVersion,
[FromBody] JsonDocument requestJsonDoc,
HttpContext context,
string deploymentName
Expand Down Expand Up @@ -66,7 +65,7 @@ string deploymentName
);
}

var url = GenerateEndpointUrl(deployment, extPath, apiVersion);
var url = GenerateEndpointUrl(deployment, extPath);

try
{
Expand All @@ -87,6 +86,7 @@ await proxyService.HttpPostStreamAsync(
var (responseContent, statusCode) = await proxyService.HttpPostAsync(
url,
deployment.EndpointKey,
context,
requestJsonDoc,
requestContext,
deployment
Expand Down Expand Up @@ -130,10 +130,11 @@ private static bool IsStreaming(JsonDocument requestJsonDoc)
: null;
}

private static Uri GenerateEndpointUrl(Deployment deployment, string extPath, string apiVersion)
private static UriBuilder GenerateEndpointUrl(Deployment deployment, string extPath)
{
var baseUrl =
$"{deployment.EndpointUrl.TrimEnd('/')}/openai/deployments/{deployment.DeploymentName.Trim()}";
return new Uri($"{baseUrl}{extPath}?api-version={apiVersion}");
return new UriBuilder(deployment.EndpointUrl.TrimEnd('/'))
{
Path = $"/openai/deployments/{deployment.DeploymentName.Trim()}{extPath}"
};
}
}
5 changes: 3 additions & 2 deletions src/AzureAIProxy/Services/IProxyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ namespace AzureAIProxy.Services;
public interface IProxyService
{
Task<(string responseContent, int statusCode)> HttpPostAsync(
Uri requestUrl,
UriBuilder requestUrl,
string endpointKey,
HttpContext context,
JsonDocument requestJsonDoc,
RequestContext requestContext,
Deployment deployment
);
Task HttpPostStreamAsync(
Uri requestUrl,
UriBuilder requestUrl,
string endpointKey,
HttpContext context,
JsonDocument requestJsonDoc,
Expand Down
27 changes: 23 additions & 4 deletions src/AzureAIProxy/Services/MockProxyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ private static int RandomDelayInMilliseconds
/// This method is used for testing purposes and does not actually send an HTTP request.
/// </summary>
public async Task<(string responseContent, int statusCode)> HttpPostAsync(
Uri requestUrl,
UriBuilder requestUrl,
string endpointKey,
HttpContext context,
JsonDocument requestJsonDoc,
RequestContext requestContext,
Deployment deployment
Expand All @@ -33,7 +34,8 @@ Deployment deployment
using var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(HttpTimeoutSeconds);

using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var requestUrlWithQuery = AppendQueryParameters(requestUrl, context);
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrlWithQuery);
requestMessage.Content = new StringContent(
requestJsonDoc.RootElement.ToString(),
Encoding.UTF8,
Expand Down Expand Up @@ -61,7 +63,7 @@ Deployment deployment
/// This method is used for testing purposes and does not actually send an HTTP request.
/// </summary>
public async Task HttpPostStreamAsync(
Uri requestUrl,
UriBuilder requestUrl,
string endpointKey,
HttpContext context,
JsonDocument requestJsonDoc,
Expand All @@ -72,7 +74,8 @@ Deployment deployment
var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(HttpTimeoutSeconds);

using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var requestUrlWithQuery = AppendQueryParameters(requestUrl, context);
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrlWithQuery);
requestMessage.Content = new StringContent(
requestJsonDoc.RootElement.ToString(),
Encoding.UTF8,
Expand Down Expand Up @@ -121,4 +124,20 @@ bool streaming
+ "\"}";
}
}

/// <summary>
/// Appends query parameters from the specified <see cref="HttpContext"/> to the given request URL.
/// </summary>
/// <param name="requestUrl">The request URL to append the query parameters to.</param>
/// <param name="context">The <see cref="HttpContext"/> containing the query parameters.</param>
/// <returns>A new <see cref="Uri"/> object with the appended query parameters.</returns>
private static Uri AppendQueryParameters(UriBuilder requestUrl, HttpContext context)
{
var queryParameters = context.Request.Query
.Where(q => !string.IsNullOrEmpty(q.Value)) // Skip parameters with empty values
.Select(q => $"{q.Key}={q.Value!}");

requestUrl.Query = string.Join("&", queryParameters);
return requestUrl.Uri;
}
}
27 changes: 23 additions & 4 deletions src/AzureAIProxy/Services/ProxyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ public class ProxyService(IHttpClientFactory httpClientFactory, IMetricService m
/// <param name="endpointKey">The endpoint key to use for authentication.</param>
/// <returns>A tuple containing the response content and the status code of the HTTP response.</returns>
public async Task<(string responseContent, int statusCode)> HttpPostAsync(
Uri requestUrl,
UriBuilder requestUrl,
string endpointKey,
HttpContext context,
JsonDocument requestJsonDoc,
RequestContext requestContext,
Deployment deployment
Expand All @@ -27,7 +28,8 @@ Deployment deployment
using var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(HttpTimeoutSeconds);

using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var requestUrlWithQuery = AppendQueryParameters(requestUrl, context);
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrlWithQuery);
requestMessage.Content = new StringContent(
requestJsonDoc.RootElement.ToString(),
Encoding.UTF8,
Expand All @@ -51,7 +53,7 @@ Deployment deployment
/// <param name="requestString">The request body as a string.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task HttpPostStreamAsync(
Uri requestUrl,
UriBuilder requestUrl,
string endpointKey,
HttpContext context,
JsonDocument requestJsonDoc,
Expand All @@ -62,7 +64,8 @@ Deployment deployment
var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(HttpTimeoutSeconds);

using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var requestUrlWithQuery = AppendQueryParameters(requestUrl, context);
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrlWithQuery);
requestMessage.Content = new StringContent(
requestJsonDoc.RootElement.ToString(),
Encoding.UTF8,
Expand All @@ -82,4 +85,20 @@ Deployment deployment
await using var responseStream = await response.Content.ReadAsStreamAsync();
await responseStream.CopyToAsync(context.Response.Body);
}

/// <summary>
/// Appends query parameters from the specified <see cref="HttpContext"/> to the given request URL.
/// </summary>
/// <param name="requestUrl">The request URL to append the query parameters to.</param>
/// <param name="context">The <see cref="HttpContext"/> containing the query parameters.</param>
/// <returns>A new <see cref="Uri"/> object with the appended query parameters.</returns>
private static Uri AppendQueryParameters(UriBuilder requestUrl, HttpContext context)
{
var queryParameters = context.Request.Query
.Where(q => !string.IsNullOrEmpty(q.Value)) // Skip parameters with empty values
.Select(q => $"{q.Key}={q.Value!}");

requestUrl.Query = string.Join("&", queryParameters);
return requestUrl.Uri;
}
}

0 comments on commit 21fc935

Please sign in to comment.