Skip to content

Commit

Permalink
[Backend API] Implement endpoint for new resource details aliencube#308
Browse files Browse the repository at this point in the history
  • Loading branch information
o-ii committed Oct 5, 2024
1 parent 265fc3a commit 402bd2a
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 6 deletions.
2 changes: 1 addition & 1 deletion infra/aspire.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ param enableRbacAuthorization bool = true
// parameters for storage account
param storageAccountName string = ''
// tableNames passed as a comma separated string from command line
param tableNames string = 'events'
param tableNames string = 'resources'

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

Expand Down
19 changes: 16 additions & 3 deletions src/AzureOpenAIProxy.ApiApp/Endpoints/AdminResourceEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static RouteHandlerBuilder AddNewAdminResource(this WebApplication app)
{
var builder = app.MapPost(AdminEndpointUrls.AdminResources, async (
[FromBody] AdminResourceDetails payload,
IAdminEventService service,
IAdminResourceService service,
ILoggerFactory loggerFactory) =>
{
var logger = loggerFactory.CreateLogger(nameof(AdminResourceEndpoints));
Expand All @@ -28,11 +28,24 @@ public static RouteHandlerBuilder AddNewAdminResource(this WebApplication app)
if (payload is null)
{
logger.LogError("No payload found");

return Results.BadRequest("Payload is null");
}

return await Task.FromResult(Results.Ok());
try
{
var result = await service.CreateResource(payload);

logger.LogInformation("Created a new resource");

return Results.Ok(result);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to create a new resource");

return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
}
})
.Accepts<AdminResourceDetails>(contentType: "application/json")
.Produces<AdminResourceDetails>(statusCode: StatusCodes.Status200OK, contentType: "application/json")
Expand Down
6 changes: 6 additions & 0 deletions src/AzureOpenAIProxy.ApiApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
// Add admin repositories
builder.Services.AddAdminEventRepository();

// Add admin resource services
builder.Services.AddAdminResourceService();

// Add admin resource repositories
builder.Services.AddAdminResourceRepository();

var app = builder.Build();

app.MapDefaultEndpoints();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Azure.Data.Tables;

using AzureOpenAIProxy.ApiApp.Configurations;
using AzureOpenAIProxy.ApiApp.Models;

namespace AzureOpenAIProxy.ApiApp.Repositories;

/// <summary>
/// This provides interfaces to the <see cref="AdminResourceRepository"/> class.
/// </summary>
public interface IAdminResourceRepository
{
/// <summary>
/// Creates a new record of resource details.
/// </summary>
/// <param name="resourceDetails">Resource details instance.</param>
/// <returns>Returns the resource details instance created.</returns>
Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails);
}

/// <summary>
/// This represents the repository entity for the admin resource.
/// </summary>
public class AdminResourceRepository(TableServiceClient tableServiceClient, StorageAccountSettings storageAccountSettings) : IAdminResourceRepository
{
private readonly TableServiceClient _tableServiceClient = tableServiceClient ?? throw new ArgumentNullException(nameof(tableServiceClient));
private readonly StorageAccountSettings _storageAccountSettings = storageAccountSettings ?? throw new ArgumentNullException(nameof(storageAccountSettings));

/// <inheritdoc />
public async Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails)
{
TableClient tableClient = await GetTableClientAsync();

await tableClient.AddEntityAsync(resourceDetails).ConfigureAwait(false);

return resourceDetails;
}

private async Task<TableClient> GetTableClientAsync()
{
TableClient tableClient = _tableServiceClient.GetTableClient(_storageAccountSettings.TableStorage.TableName);

await tableClient.CreateIfNotExistsAsync().ConfigureAwait(false);

return tableClient;
}
}

/// <summary>
/// This represents the extension class for <see cref="IServiceCollection"/>
/// </summary>
public static class AdminResourceRepositoryExtensions
{
/// <summary>
/// Adds the <see cref="AdminResourceRepository"/> instance to the service collection.
/// </summary>
/// <param name="services"><see cref="IServiceCollection"/> instance.</param>
/// <returns>Returns <see cref="IServiceCollection"/> instance.</returns>
public static IServiceCollection AddAdminResourceRepository(this IServiceCollection services)
{
services.AddScoped<IAdminResourceRepository, AdminResourceRepository>();

return services;
}
}
57 changes: 57 additions & 0 deletions src/AzureOpenAIProxy.ApiApp/Services/AdminResourceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using AzureOpenAIProxy.ApiApp.Models;
using AzureOpenAIProxy.ApiApp.Repositories;

namespace AzureOpenAIProxy.ApiApp.Services;

/// <summary>
/// This provides interfaces to the <see cref="AdminResourceService"/> class.
/// </summary>
public interface IAdminResourceService
{
/// <summary>
/// Creates a new resource.
/// </summary>
/// <param name="resourceDetails">Resource payload.</param>
/// <returns>Returns the resource payload created.</returns>
Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails);
}

/// <summary>
/// This represents the service entity for admin resource.
/// </summary>
public class AdminResourceService : IAdminResourceService
{
private readonly IAdminResourceRepository _repository;

public AdminResourceService(IAdminResourceRepository repository)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
}

/// <inheritdoc />
public async Task<AdminResourceDetails> CreateResource(AdminResourceDetails resourceDetails)
{
resourceDetails.PartitionKey = PartitionKeys.ResourceDetails;
resourceDetails.RowKey = resourceDetails.ResourceId.ToString();

var result = await _repository.CreateResource(resourceDetails).ConfigureAwait(false);
return result;
}
}

/// <summary>
/// This represents the extension class for <see cref="IServiceCollection"/>.
/// </summary>
public static class AdminResourceServiceExtensions
{
/// <summary>
/// Adds the <see cref="AdminResourceService"/> instance to the service collection.
/// </summary>
/// <param name="services"><see cref="IServiceCollection"/> instance.</param>
/// <returns>Returns <see cref="IServiceCollection"/> instance.</returns>
public static IServiceCollection AddAdminResourceService(this IServiceCollection services)
{
services.AddScoped<IAdminResourceService, AdminResourceService>();
return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
},
"KeyVault": {
"VaultUri": "https://{{key-vault-name}}.vault.azure.net/",
"SecretName": "azure-openai-instances"
"SecretNames": {
"OpenAI": "azure-openai-instances",
"Storage": "storage-connection-string"
}
}
}
}
2 changes: 1 addition & 1 deletion src/AzureOpenAIProxy.ApiApp/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
},
"StorageAccount": {
"TableStorage": {
"TableName": "events"
"TableName": "resources"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Azure;
using Azure.Data.Tables;

using AzureOpenAIProxy.ApiApp.Configurations;
using AzureOpenAIProxy.ApiApp.Models;
using AzureOpenAIProxy.ApiApp.Repositories;

using FluentAssertions;

using Microsoft.Extensions.DependencyInjection;

using NSubstitute;
using NSubstitute.ExceptionExtensions;

namespace AzureOpenAIProxy.ApiApp.Tests.Repositories;

public class AdminResourceRepositoryTests
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Azure;

using AzureOpenAIProxy.ApiApp.Models;
using AzureOpenAIProxy.ApiApp.Repositories;
using AzureOpenAIProxy.ApiApp.Services;

using FluentAssertions;

using Microsoft.Extensions.DependencyInjection;

using NSubstitute;
using NSubstitute.ExceptionExtensions;

namespace AzureOpenAIProxy.ApiApp.Tests.Services;

public class AdminResourceServiceTests
{
}

0 comments on commit 402bd2a

Please sign in to comment.