11using System . Text . Json ;
2+ using AiRouter . AspNetCore ;
23using AiRouter . Providers ;
34using AiRouter . Routing ;
45using Microsoft . AspNetCore . Http ;
@@ -8,31 +9,47 @@ namespace Microsoft.AspNetCore.Builder;
89
910public static class AiRouterEndpointRouteBuilderExtensions
1011{
11- public static IEndpointRouteBuilder MapAiRouterOpenAiEndpoints ( this IEndpointRouteBuilder endpoints )
12+ public static IEndpointRouteBuilder MapAiRouterOpenAiEndpoints (
13+ this IEndpointRouteBuilder endpoints ,
14+ string ? bearerKey = null )
1215 {
1316 ArgumentNullException . ThrowIfNull ( endpoints ) ;
1417
15- endpoints . MapPost ( "/v1/chat/completions" , OpenAiEndpointHandlers . ChatAsync ) ;
16- endpoints . MapPost ( "/v1/responses" , OpenAiEndpointHandlers . ResponsesAsync ) ;
17- endpoints . MapGet ( "/v1/models" , OpenAiEndpointHandlers . ModelsAsync ) ;
18+ endpoints . MapPost ( "/v1/chat/completions" , ( HttpContext context , IAiRouter router ) =>
19+ OpenAiEndpointHandlers . ChatAsync ( context , router , bearerKey ) ) ;
20+ endpoints . MapPost ( "/v1/responses" , ( HttpContext context , IAiRouter router ) =>
21+ OpenAiEndpointHandlers . ResponsesAsync ( context , router , bearerKey ) ) ;
22+ endpoints . MapGet ( "/v1/models" , ( HttpContext context , IProviderManager providers , IRouteStore routes ) =>
23+ OpenAiEndpointHandlers . ModelsAsync ( context , providers , routes , bearerKey ) ) ;
1824
1925 return endpoints ;
2026 }
2127}
2228
2329internal static class OpenAiEndpointHandlers
2430{
25- public static Task ChatAsync ( HttpContext context , IAiRouter router ) =>
26- RouteAsync ( context , router . ChatAsync ) ;
31+ private static readonly JsonSerializerOptions Json = new ( JsonSerializerDefaults . Web ) ;
2732
28- public static Task ResponsesAsync ( HttpContext context , IAiRouter router ) =>
29- RouteAsync ( context , router . ResponsesAsync ) ;
33+ public static async Task ChatAsync ( HttpContext context , IAiRouter router , string ? bearerKey )
34+ {
35+ if ( ! await BearerKeyAuthorizer . RequireAsync ( context , bearerKey ) . ConfigureAwait ( false ) ) return ;
36+ await RouteAsync ( context , router . ChatAsync ) . ConfigureAwait ( false ) ;
37+ }
38+
39+ public static async Task ResponsesAsync ( HttpContext context , IAiRouter router , string ? bearerKey )
40+ {
41+ if ( ! await BearerKeyAuthorizer . RequireAsync ( context , bearerKey ) . ConfigureAwait ( false ) ) return ;
42+ await RouteAsync ( context , router . ResponsesAsync ) . ConfigureAwait ( false ) ;
43+ }
3044
3145 public static async Task ModelsAsync (
3246 HttpContext context ,
3347 IProviderManager providerManager ,
34- IRouteStore routeStore )
48+ IRouteStore routeStore ,
49+ string ? bearerKey )
3550 {
51+ if ( ! await BearerKeyAuthorizer . RequireAsync ( context , bearerKey ) . ConfigureAwait ( false ) ) return ;
52+
3653 var ids = new HashSet < string > ( StringComparer . Ordinal ) ;
3754 var routes = await routeStore . ListAsync ( context . RequestAborted ) . ConfigureAwait ( false ) ;
3855 foreach ( var route in routes . Where ( static route => route . Enabled ) )
@@ -80,11 +97,7 @@ public static async Task ModelsAsync(
8097 } )
8198 . ToArray ( ) ;
8299
83- context . Response . StatusCode = StatusCodes . Status200OK ;
84- context . Response . ContentType = "application/json" ;
85- await context . Response . WriteAsync (
86- JsonSerializer . Serialize ( new { @object = "list" , data } ) ,
87- context . RequestAborted ) . ConfigureAwait ( false ) ;
100+ await WriteJsonAsync ( context , StatusCodes . Status200OK , new { @object = "list" , data } ) . ConfigureAwait ( false ) ;
88101 }
89102
90103 private static async Task RouteAsync (
@@ -118,9 +131,7 @@ await WriteErrorAsync(context, StatusCodes.Status400BadRequest, "Model is requir
118131 }
119132
120133 var model = modelElement . GetString ( ) ! ;
121- var stream = root . TryGetProperty ( "stream" , out var streamElement ) &&
122- streamElement . ValueKind == JsonValueKind . True ;
123-
134+ var stream = root . TryGetProperty ( "stream" , out var streamElement ) && streamElement . ValueKind == JsonValueKind . True ;
124135 var result = await send ( model , root . Clone ( ) , stream , context . RequestAborted ) . ConfigureAwait ( false ) ;
125136 await WriteRouterResultAsync ( context , result ) . ConfigureAwait ( false ) ;
126137 }
@@ -136,7 +147,6 @@ private static async Task WriteRouterResultAsync(HttpContext context, RouterResu
136147 ProviderFailureKind . RateLimited => "rate_limit_error" ,
137148 _ => "server_error"
138149 } ;
139-
140150 await WriteErrorAsync (
141151 context ,
142152 result . StatusCode > 0 ? result . StatusCode : StatusCodes . Status500InternalServerError ,
@@ -146,10 +156,8 @@ await WriteErrorAsync(
146156 }
147157
148158 context . Response . StatusCode = result . StatusCode > 0 ? result . StatusCode : StatusCodes . Status200OK ;
149- if ( ! string . IsNullOrWhiteSpace ( result . ProviderId ) )
150- context . Response . Headers [ "X-AiRouter-Provider" ] = result . ProviderId ;
151- if ( ! string . IsNullOrWhiteSpace ( result . Model ) )
152- context . Response . Headers [ "X-AiRouter-Model" ] = result . Model ;
159+ if ( ! string . IsNullOrWhiteSpace ( result . ProviderId ) ) context . Response . Headers [ "X-AiRouter-Provider" ] = result . ProviderId ;
160+ if ( ! string . IsNullOrWhiteSpace ( result . Model ) ) context . Response . Headers [ "X-AiRouter-Model" ] = result . Model ;
153161
154162 if ( result . Stream is not null )
155163 {
@@ -164,11 +172,8 @@ await WriteErrorAsync(
164172 await context . Response . WriteAsync ( body . GetRawText ( ) , context . RequestAborted ) . ConfigureAwait ( false ) ;
165173 }
166174
167- private static async Task WriteErrorAsync ( HttpContext context , int statusCode , string message , string type )
168- {
169- context . Response . StatusCode = statusCode ;
170- context . Response . ContentType = "application/json" ;
171- var payload = JsonSerializer . Serialize ( new
175+ private static Task WriteErrorAsync ( HttpContext context , int statusCode , string message , string type ) =>
176+ WriteJsonAsync ( context , statusCode , new
172177 {
173178 error = new
174179 {
@@ -178,6 +183,11 @@ private static async Task WriteErrorAsync(HttpContext context, int statusCode, s
178183 code = ( string ? ) null
179184 }
180185 } ) ;
181- await context . Response . WriteAsync ( payload , context . RequestAborted ) . ConfigureAwait ( false ) ;
186+
187+ private static async Task WriteJsonAsync ( HttpContext context , int statusCode , object value )
188+ {
189+ context . Response . StatusCode = statusCode ;
190+ context . Response . ContentType = "application/json" ;
191+ await context . Response . WriteAsync ( JsonSerializer . Serialize ( value , Json ) , context . RequestAborted ) . ConfigureAwait ( false ) ;
182192 }
183193}
0 commit comments