Skip to content

Commit 30fd8a6

Browse files
authored
[OpenAPI] Add endpoint for list of events #179 (#259)
1 parent c7ff077 commit 30fd8a6

File tree

8 files changed

+218
-34
lines changed

8 files changed

+218
-34
lines changed

src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace AzureOpenAIProxy.ApiApp.Endpoints;
1+
namespace AzureOpenAIProxy.ApiApp.Endpoints;
22

33
/// <summary>
44
/// This represents the collection of the endpoint URLs.
@@ -14,4 +14,9 @@ public static class EndpointUrls
1414
/// Declares the chat completions endpoint.
1515
/// </summary>
1616
public const string ChatCompletions = "/openai/deployments/{deploymentName}/chat/completions";
17-
}
17+
18+
/// <summary>
19+
/// Declares the event endpoint.
20+
/// </summary>
21+
public const string Events = "/events";
22+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Text.Json;
2+
3+
using AzureOpenAIProxy.ApiApp.Models;
4+
5+
namespace AzureOpenAIProxy.ApiApp.Endpoints;
6+
7+
/// <summary>
8+
/// This represents the endpoint entity for events that the logged user joined.
9+
/// </summary>
10+
public static class EventEndpoint
11+
{
12+
/// <summary>
13+
/// Adds the event endpoint.
14+
/// </summary>
15+
/// <param name="app"><see cref="WebApplication"/> instance.</param>
16+
/// <returns>Returns <see cref="RouteHandlerBuilder"/> instance.</returns>
17+
public static RouteHandlerBuilder AddEventList(this WebApplication app)
18+
{
19+
var builder = app.MapGet(EndpointUrls.Events, () =>
20+
{
21+
// TODO: Issue #179 https://github.com/aliencube/azure-openai-sdk-proxy/issues/179
22+
return Results.Ok();
23+
})
24+
.Produces<List<EventDetails>>(statusCode: StatusCodes.Status200OK, contentType: "application/json")
25+
.Produces(statusCode: StatusCodes.Status401Unauthorized)
26+
.Produces<string>(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain")
27+
.WithTags("events")
28+
.WithName("GetEvents")
29+
.WithOpenApi(operation =>
30+
{
31+
operation.Description = "Gets all events' details that the user joined.";
32+
operation.Summary = "This endpoint gets all events' details that the user joined.";
33+
34+
return operation;
35+
});
36+
37+
return builder;
38+
}
39+
}

src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Azure.Identity;
1+
using Azure.Identity;
22
using Azure.Security.KeyVault.Secrets;
33

44
using AzureOpenAIProxy.ApiApp.Builders;
@@ -132,4 +132,4 @@ public static IServiceCollection AddOpenApiService(this IServiceCollection servi
132132

133133
return services;
134134
}
135-
}
135+
}

src/AzureOpenAIProxy.ApiApp/Filters/OpenApiTagFilter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
1616
[
1717
new OpenApiTag { Name = "weather", Description = "Weather forecast operations" },
1818
new OpenApiTag { Name = "openai", Description = "Azure OpenAI operations" },
19-
new OpenApiTag { Name = "admin", Description = "Admin for organizing events" }
19+
new OpenApiTag { Name = "admin", Description = "Admin for organizing events" },
20+
new OpenApiTag { Name = "events", Description = "User events" }
2021
];
2122
}
2223
}

src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,15 @@
33
/// <summary>
44
/// This represent the event detail data for response by admin event endpoint.
55
/// </summary>
6-
public class AdminEventDetails
6+
public class AdminEventDetails : EventDetails
77
{
88
/// <summary>
9-
/// Gets or sets the event id.
10-
/// </summary>
11-
public required string? EventId { get; set; }
12-
13-
/// <summary>
14-
/// Gets or sets the event title name.
15-
/// </summary>
16-
public required string? Title { get; set; }
17-
18-
/// <summary>
19-
/// Gets or sets the event summary.
20-
/// </summary>
21-
public required string? Summary { get; set; }
22-
23-
/// <summary>
24-
/// Gets or sets the event description.
9+
/// Gets or sets the event description.
2510
/// </summary>
2611
public string? Description { get; set; }
2712

2813
/// <summary>
29-
/// Gets or sets the event start date.
14+
/// Gets or sets the event start date.
3015
/// </summary>
3116
public required DateTimeOffset? DateStart { get; set; }
3217

@@ -46,7 +31,7 @@ public class AdminEventDetails
4631
public required bool? IsActive { get; set; }
4732

4833
/// <summary>
49-
/// Gets or sets the event organizer name.
34+
/// Gets or sets the event organizer name.
5035
/// </summary>
5136
public required string? OrganizerName { get; set; }
5237

@@ -64,14 +49,4 @@ public class AdminEventDetails
6449
/// Gets or sets the event coorganizer email.
6550
/// </summary>
6651
public string? CoorganizerEmail { get; set; }
67-
68-
/// <summary>
69-
/// Gets or sets the Azure OpenAI Service request max token capacity.
70-
/// </summary>
71-
public required int? MaxTokenCap { get; set; }
72-
73-
/// <summary>
74-
/// Gets or sets the Azure OpenAI Service daily request capacity.
75-
/// </summary>
76-
public required int? DailyRequestCap { get; set; }
7752
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.Json.Serialization;
3+
4+
using AzureOpenAIProxy.ApiApp.Models;
5+
6+
/// <summary>
7+
/// This represents the event's detailed data for response by EventEndpoint.
8+
/// </summary>
9+
public class EventDetails
10+
{
11+
/// <summary>
12+
/// Gets or sets the event id.
13+
/// </summary>
14+
public required string? EventId { get; set; }
15+
16+
/// <summary>
17+
/// Gets or sets the event title name.
18+
/// </summary>
19+
public required string? Title { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the event summary.
23+
/// </summary>
24+
public required string? Summary { get; set; }
25+
26+
/// <summary>
27+
/// Gets or sets the Azure OpenAI Service request max token capacity.
28+
/// </summary>
29+
public required int? MaxTokenCap { get; set; }
30+
31+
/// <summary>
32+
/// Gets or sets the Azure OpenAI Service daily request capacity.
33+
/// </summary>
34+
public required int? DailyRequestCap { get; set; }
35+
}

src/AzureOpenAIProxy.ApiApp/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
app.AddWeatherForecast();
4040
app.AddChatCompletions();
4141

42+
// Event Endpoints
43+
app.AddEventList();
44+
4245
// Admin Endpoints
4346
app.AddAdminEvents();
4447
app.AddAdminEventList();
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using System.Text.Json;
2+
3+
using AzureOpenAIProxy.AppHost.Tests.Fixtures;
4+
5+
using FluentAssertions;
6+
7+
using IdentityModel.Client;
8+
9+
namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints;
10+
11+
public class GetEventsOpenApiTests(AspireAppHostFixture host) : IClassFixture<AspireAppHostFixture>
12+
{
13+
[Fact]
14+
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path()
15+
{
16+
// Arrange
17+
using var httpClient = host.App!.CreateHttpClient("apiapp");
18+
19+
// Act
20+
var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json");
21+
var apiDocument = JsonSerializer.Deserialize<JsonDocument>(json);
22+
23+
// Assert
24+
var result = apiDocument!.RootElement.GetProperty("paths")
25+
.TryGetProperty("/events", out var property) ? property : default;
26+
result.ValueKind.Should().Be(JsonValueKind.Object);
27+
}
28+
29+
[Fact]
30+
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Verb()
31+
{
32+
// Arrange
33+
using var httpClient = host.App!.CreateHttpClient("apiapp");
34+
35+
// Act
36+
var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json");
37+
var apiDocument = JsonSerializer.Deserialize<JsonDocument>(json);
38+
39+
// Assert
40+
var result = apiDocument!.RootElement.GetProperty("paths")
41+
.GetProperty("/events")
42+
.TryGetProperty("get", out var property) ? property : default;
43+
result.ValueKind.Should().Be(JsonValueKind.Object);
44+
}
45+
46+
[Theory]
47+
[InlineData("events")]
48+
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tags(string tag)
49+
{
50+
// Arrange
51+
using var httpClient = host.App!.CreateHttpClient("apiapp");
52+
53+
// Act
54+
var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json");
55+
var apiDocument = JsonSerializer.Deserialize<JsonDocument>(json);
56+
57+
// Assert
58+
var result = apiDocument!.RootElement.GetProperty("paths")
59+
.GetProperty("/events")
60+
.GetProperty("get")
61+
.TryGetProperty("tags", out var property) ? property : default;
62+
result.ValueKind.Should().Be(JsonValueKind.Array);
63+
result.EnumerateArray().Select(p => p.GetString()).Should().Contain(tag);
64+
}
65+
66+
[Theory]
67+
[InlineData("summary")]
68+
[InlineData("operationId")]
69+
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Value(string attribute)
70+
{
71+
// Arrange
72+
using var httpClient = host.App!.CreateHttpClient("apiapp");
73+
74+
// Act
75+
var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json");
76+
var apiDocument = JsonSerializer.Deserialize<JsonDocument>(json);
77+
78+
// Assert
79+
var result = apiDocument!.RootElement.GetProperty("paths")
80+
.GetProperty("/events")
81+
.GetProperty("get")
82+
.TryGetProperty(attribute, out var property) ? property : default;
83+
result.ValueKind.Should().Be(JsonValueKind.String);
84+
}
85+
86+
[Theory]
87+
[InlineData("responses")]
88+
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Object(string attribute)
89+
{
90+
// Arrange
91+
using var httpClient = host.App!.CreateHttpClient("apiapp");
92+
93+
// Act
94+
var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json");
95+
var apiDocument = JsonSerializer.Deserialize<JsonDocument>(json);
96+
97+
// Assert
98+
var result = apiDocument!.RootElement.GetProperty("paths")
99+
.GetProperty("/events")
100+
.GetProperty("get")
101+
.TryGetProperty(attribute, out var property) ? property : default;
102+
result.ValueKind.Should().Be(JsonValueKind.Object);
103+
}
104+
105+
[Theory]
106+
[InlineData("200")]
107+
[InlineData("401")]
108+
[InlineData("500")]
109+
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response(string attribute)
110+
{
111+
// Arrange
112+
using var httpClient = host.App!.CreateHttpClient("apiapp");
113+
114+
// Act
115+
var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json");
116+
var apiDocument = JsonSerializer.Deserialize<JsonDocument>(json);
117+
118+
// Assert
119+
var result = apiDocument!.RootElement.GetProperty("paths")
120+
.GetProperty("/events")
121+
.GetProperty("get")
122+
.GetProperty("responses")
123+
.TryGetProperty(attribute, out var property) ? property : default;
124+
result.ValueKind.Should().Be(JsonValueKind.Object);
125+
}
126+
}

0 commit comments

Comments
 (0)