Skip to content

Commit e27891b

Browse files
committed
[Backend API] Implement endpoint for new resource details aliencube#308
1 parent 265fc3a commit e27891b

File tree

9 files changed

+186
-5
lines changed

9 files changed

+186
-5
lines changed

infra/aspire.bicep

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ param enableRbacAuthorization bool = true
2424
// parameters for storage account
2525
param storageAccountName string = ''
2626
// tableNames passed as a comma separated string from command line
27-
param tableNames string = 'events'
27+
param tableNames string = 'resources'
2828

2929
var abbrs = loadJsonContent('./abbreviations.json')
3030

src/AzureOpenAIProxy.ApiApp/Endpoints/AdminResourceEndpoints.cs

+15-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static RouteHandlerBuilder AddNewAdminResource(this WebApplication app)
1919
{
2020
var builder = app.MapPost(AdminEndpointUrls.AdminResources, async (
2121
[FromBody] AdminResourceDetails payload,
22-
IAdminEventService service,
22+
IAdminResourceService service,
2323
ILoggerFactory loggerFactory) =>
2424
{
2525
var logger = loggerFactory.CreateLogger(nameof(AdminResourceEndpoints));
@@ -32,7 +32,20 @@ public static RouteHandlerBuilder AddNewAdminResource(this WebApplication app)
3232
return Results.BadRequest("Payload is null");
3333
}
3434

35-
return await Task.FromResult(Results.Ok());
35+
try
36+
{
37+
var result = await service.CreateResource(payload);
38+
39+
logger.LogInformation("Created a new resource");
40+
41+
return Results.Ok(result);
42+
}
43+
catch (Exception ex)
44+
{
45+
logger.LogError(ex, "Failed to create a new resource");
46+
47+
return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
48+
}
3649
})
3750
.Accepts<AdminResourceDetails>(contentType: "application/json")
3851
.Produces<AdminResourceDetails>(statusCode: StatusCodes.Status200OK, contentType: "application/json")

src/AzureOpenAIProxy.ApiApp/Program.cs

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
// Add admin repositories
2929
builder.Services.AddAdminEventRepository();
3030

31+
// Add admin resource services
32+
builder.Services.AddAdminResourceService();
33+
34+
// Add admin resource repositories
35+
builder.Services.AddAdminResourceRepository();
36+
3137
var app = builder.Build();
3238

3339
app.MapDefaultEndpoints();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using Azure.Data.Tables;
2+
3+
using AzureOpenAIProxy.ApiApp.Configurations;
4+
using AzureOpenAIProxy.ApiApp.Models;
5+
6+
namespace AzureOpenAIProxy.ApiApp.Repositories;
7+
8+
/// <summary>
9+
/// This provides interfaces to the <see cref="AdminResourceRepository"/> class.
10+
/// </summary>
11+
public interface IAdminResourceRepository
12+
{
13+
/// <summary>
14+
/// Creates a new record of resource details.
15+
/// </summary>
16+
/// <param name="resourceDetails">Resource details instance.</param>
17+
/// <returns>Returns the resource details instance created.</returns>
18+
Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails);
19+
}
20+
21+
/// <summary>
22+
/// This represents the repository entity for the admin resource.
23+
/// </summary>
24+
public class AdminResourceRepository(TableServiceClient tableServiceClient, StorageAccountSettings storageAccountSettings) : IAdminResourceRepository
25+
{
26+
private readonly TableServiceClient _tableServiceClient = tableServiceClient ?? throw new ArgumentNullException(nameof(tableServiceClient));
27+
private readonly StorageAccountSettings _storageAccountSettings = storageAccountSettings ?? throw new ArgumentNullException(nameof(storageAccountSettings));
28+
29+
/// <inheritdoc />
30+
public async Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails)
31+
{
32+
TableClient tableClient = await GetTableClientAsync();
33+
34+
await tableClient.AddEntityAsync(resourceDetails).ConfigureAwait(false);
35+
36+
return resourceDetails;
37+
}
38+
39+
private async Task<TableClient> GetTableClientAsync()
40+
{
41+
TableClient tableClient = _tableServiceClient.GetTableClient(_storageAccountSettings.TableStorage.TableName);
42+
43+
await tableClient.CreateIfNotExistsAsync().ConfigureAwait(false);
44+
45+
return tableClient;
46+
}
47+
}
48+
49+
/// <summary>
50+
/// This represents the extension class for <see cref="IServiceCollection"/>
51+
/// </summary>
52+
public static class AdminResourceRepositoryExtensions
53+
{
54+
/// <summary>
55+
/// Adds the <see cref="AdminResourceRepository"/> instance to the service collection.
56+
/// </summary>
57+
/// <param name="services"><see cref="IServiceCollection"/> instance.</param>
58+
/// <returns>Returns <see cref="IServiceCollection"/> instance.</returns>
59+
public static IServiceCollection AddAdminResourceRepository(this IServiceCollection services)
60+
{
61+
services.AddScoped<IAdminResourceRepository, AdminResourceRepository>();
62+
63+
return services;
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using AzureOpenAIProxy.ApiApp.Models;
2+
using AzureOpenAIProxy.ApiApp.Repositories;
3+
4+
namespace AzureOpenAIProxy.ApiApp.Services;
5+
6+
/// <summary>
7+
/// This provides interfaces to the <see cref="AdminResourceService"/> class.
8+
/// </summary>
9+
public interface IAdminResourceService
10+
{
11+
/// <summary>
12+
/// Creates a new resource.
13+
/// </summary>
14+
/// <param name="resourceDetails">Resource payload.</param>
15+
/// <returns>Returns the resource payload created.</returns>
16+
Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails);
17+
}
18+
19+
/// <summary>
20+
/// This represents the service entity for admin resource.
21+
/// </summary>
22+
public class AdminResourceService : IAdminResourceService
23+
{
24+
private readonly IAdminResourceRepository _repository;
25+
26+
public AdminResourceService(IAdminResourceRepository repository)
27+
{
28+
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
29+
}
30+
31+
/// <inheritdoc />
32+
public async Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails)
33+
{
34+
resourceDetails.PartitionKey = PartitionKeys.ResourceDetails;
35+
resourceDetails.RowKey = resourceDetails.ResourceId.ToString();
36+
37+
var result = await _repository.CreateResource(resourceDetails).ConfigureAwait(false);
38+
return result;
39+
}
40+
}
41+
42+
/// <summary>
43+
/// This represents the extension class for <see cref="IServiceCollection"/>.
44+
/// </summary>
45+
public static class AdminResourceServiceExtensions
46+
{
47+
/// <summary>
48+
/// Adds the <see cref="AdminResourceService"/> instance to the service collection.
49+
/// </summary>
50+
/// <param name="services"><see cref="IServiceCollection"/> instance.</param>
51+
/// <returns>Returns <see cref="IServiceCollection"/> instance.</returns>
52+
public static IServiceCollection AddAdminResourceService(this IServiceCollection services)
53+
{
54+
services.AddScoped<IAdminResourceService, AdminResourceService>();
55+
return services;
56+
}
57+
}

src/AzureOpenAIProxy.ApiApp/appsettings.Development.sample.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
},
2222
"KeyVault": {
2323
"VaultUri": "https://{{key-vault-name}}.vault.azure.net/",
24-
"SecretName": "azure-openai-instances"
24+
"SecretNames": {
25+
"OpenAI": "azure-openai-instances",
26+
"Storage": "storage-connection-string"
27+
}
2528
}
2629
}
2730
}

src/AzureOpenAIProxy.ApiApp/appsettings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
"StorageAccount": {
3434
"TableStorage": {
35-
"TableName": "events"
35+
"TableName": "resources"
3636
}
3737
}
3838
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Azure;
2+
using Azure.Data.Tables;
3+
4+
using AzureOpenAIProxy.ApiApp.Configurations;
5+
using AzureOpenAIProxy.ApiApp.Models;
6+
using AzureOpenAIProxy.ApiApp.Repositories;
7+
8+
using FluentAssertions;
9+
10+
using Microsoft.Extensions.DependencyInjection;
11+
12+
using NSubstitute;
13+
using NSubstitute.ExceptionExtensions;
14+
15+
namespace AzureOpenAIProxy.ApiApp.Tests.Repositories;
16+
17+
public class AdminResourceRepositoryTests
18+
{
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Azure;
2+
3+
using AzureOpenAIProxy.ApiApp.Models;
4+
using AzureOpenAIProxy.ApiApp.Repositories;
5+
using AzureOpenAIProxy.ApiApp.Services;
6+
7+
using FluentAssertions;
8+
9+
using Microsoft.Extensions.DependencyInjection;
10+
11+
using NSubstitute;
12+
using NSubstitute.ExceptionExtensions;
13+
14+
namespace AzureOpenAIProxy.ApiApp.Tests.Services;
15+
16+
public class AdminResourceServiceTests
17+
{
18+
}

0 commit comments

Comments
 (0)