From f761405771e79d67a0ae9ad6a4c865c5db33ca61 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Thu, 28 May 2026 21:35:31 +0200 Subject: [PATCH] Add project files. --- Musify.WebApi.slnx | 3 + WebApi/AppSettings.Development.json | 17 +++ WebApi/AppSettings.json | 94 +++++++++++++ .../PlayLists/CreatePlayListRequest.cs | 6 + .../RequestPlayListPictureUploadRequest.cs | 6 + .../PlayLists/UpdatePlayListRequest.cs | 6 + .../Tracks/CreateTrackRequest.cs | 6 + .../Tracks/RequestTrackUploadUrlsRequest.cs | 9 ++ .../Users/CreateUserRequest.cs | 7 + WebApi/Endpoints/PlayListEndpoints.cs | 130 ++++++++++++++++++ WebApi/Endpoints/TrackEndpoints.cs | 119 ++++++++++++++++ WebApi/Endpoints/UserEndpoints.cs | 78 +++++++++++ WebApi/Extensions/ResultHttpExtensions.cs | 35 +++++ .../Extensions/ServiceCollectionExtensions.cs | 50 +++++++ WebApi/Options/OpenTelemetryOptions.cs | 11 ++ WebApi/Program.cs | 24 ++++ WebApi/Properties/launchSettings.json | 14 ++ WebApi/WebApi.csproj | 44 ++++++ WebApi/WebApi.http | 6 + 19 files changed, 665 insertions(+) create mode 100644 Musify.WebApi.slnx create mode 100644 WebApi/AppSettings.Development.json create mode 100644 WebApi/AppSettings.json create mode 100644 WebApi/DataTransferObjects/PlayLists/CreatePlayListRequest.cs create mode 100644 WebApi/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs create mode 100644 WebApi/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs create mode 100644 WebApi/DataTransferObjects/Tracks/CreateTrackRequest.cs create mode 100644 WebApi/DataTransferObjects/Tracks/RequestTrackUploadUrlsRequest.cs create mode 100644 WebApi/DataTransferObjects/Users/CreateUserRequest.cs create mode 100644 WebApi/Endpoints/PlayListEndpoints.cs create mode 100644 WebApi/Endpoints/TrackEndpoints.cs create mode 100644 WebApi/Endpoints/UserEndpoints.cs create mode 100644 WebApi/Extensions/ResultHttpExtensions.cs create mode 100644 WebApi/Extensions/ServiceCollectionExtensions.cs create mode 100644 WebApi/Options/OpenTelemetryOptions.cs create mode 100644 WebApi/Program.cs create mode 100644 WebApi/Properties/launchSettings.json create mode 100644 WebApi/WebApi.csproj create mode 100644 WebApi/WebApi.http diff --git a/Musify.WebApi.slnx b/Musify.WebApi.slnx new file mode 100644 index 0000000..c239259 --- /dev/null +++ b/Musify.WebApi.slnx @@ -0,0 +1,3 @@ + + + diff --git a/WebApi/AppSettings.Development.json b/WebApi/AppSettings.Development.json new file mode 100644 index 0000000..16ecf29 --- /dev/null +++ b/WebApi/AppSettings.Development.json @@ -0,0 +1,17 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "Default": "" + }, + "Storage": { + "BucketName": "", + "Routes": { + "Uploads": "" + } + } +} \ No newline at end of file diff --git a/WebApi/AppSettings.json b/WebApi/AppSettings.json new file mode 100644 index 0000000..721a2b5 --- /dev/null +++ b/WebApi/AppSettings.json @@ -0,0 +1,94 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "Default": "" + }, + "PlayListConfiguration": { + "Routes": { + "ParentFolders": "PlayLists", + "OriginalPicturesFolder": "OriginalPictures", + "SmallPicturesFolder": "SmallPictures", + "MediumPicturesFolder": "MediumPictures", + "LargePicturesFolder": "LargePictures", + "PresetOriginalPicture": "PresetOriginalPicture.webp", + "PresetSmallPicture": "PresetSmallPicture.webp", + "PresetMediumPicture": "PresetMediumPicture.webp", + "PresetLargePicture": "PresetLargePicture.webp" + }, + "PicturesSizes": { + "SmallPictureWidth": 128, + "SmallPictureHeight": 128, + "MediumPictureWidth": 256, + "MediumPictureHeight": 256, + "LargePictureWidth": 512, + "LargePictureHeight": 512 + } + }, + "Keycloak": { + "Address": "1", + "Realm": "1", + "Username": "1", + "Password": "1" + }, + "Database": { + "ConnectionString": "Host=localhost;Port=59000;Database=musify_db;Username=postgres;Password=postgres" + }, + "ApplicationStorage": { + "BucketName": "webapi-storage" + }, + "InfrastructureStorage": { + "Address": "http://localhost:8333", + "AccessKey": "admin_access_key", + "SecretAccessKey": "admin_secret_key", + "ForcePathStyle": true, + "UseHttp": true + }, + "Messaging": { + "Address": "rabbitmq://127.0.0.1:5672", + "Username": "guest", + "Password": "guest" + }, + "OpenTelemetry": { + "OtlpEndpoint": "http://localhost:4317" + }, + "TrackConfiguration": { + "Routes": { + "ParentFolder": "Tracks", + "OriginalPicturesFolder": "OriginalPictures", + "SmallPicturesFolder": "SmallPictures", + "MediumPicturesFolder": "MediumPictures", + "LargePicturesFolder": "LargePictures", + "PresetOriginalPicture": "PresetOriginalPicture.webp", + "PresetSmallPicture": "PresetSmallPicture.webp", + "PresetMediumPicture": "PresetMediumPicture.webp", + "PresetLargePicture": "PresetLargePicture.webp", + "OriginalAudiosFolder": "OriginalAudios", + "ProcessedAudioFolder": "ProcessedAudios" + }, + "PicturesSizes": { + "SmallPictureWidth": 128, + "SmallPictureHeight": 128, + "MediumPictureWidth": 256, + "MediumPictureHeight": 256, + "LargePictureWidth": 512, + "LargePictureHeight": 512 + } + }, + "AudioTranscoder": { + "Routes": { + "WorkingDirectory": "D:\\tempsFilesDev" + }, + "TranscodingTimeout": "00:05:00" + }, + "Workers": { + "Routes": { + "TemporaryFilesDirectory": "" + } + } +} \ No newline at end of file diff --git a/WebApi/DataTransferObjects/PlayLists/CreatePlayListRequest.cs b/WebApi/DataTransferObjects/PlayLists/CreatePlayListRequest.cs new file mode 100644 index 0000000..f6a5e62 --- /dev/null +++ b/WebApi/DataTransferObjects/PlayLists/CreatePlayListRequest.cs @@ -0,0 +1,6 @@ +namespace WebApi.DataTransferObjects.PlayLists; + +public record CreatePlayListRequest( + string Name, + string Description, + Guid? PictureIntentId); diff --git a/WebApi/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs b/WebApi/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs new file mode 100644 index 0000000..4998aa1 --- /dev/null +++ b/WebApi/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs @@ -0,0 +1,6 @@ +namespace WebApi.DataTransferObjects.PlayLists; + +public record RequestPlayListPictureUploadRequest( + string FileType, + string ContentType, + long? ExpectedSizeBytes = null); diff --git a/WebApi/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs b/WebApi/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs new file mode 100644 index 0000000..083a51d --- /dev/null +++ b/WebApi/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs @@ -0,0 +1,6 @@ +namespace WebApi.DataTransferObjects.PlayLists; + +public record UpdatePlayListRequest( + string? NewName, + string? NewDescription, + Guid? NewPictureIntentId); diff --git a/WebApi/DataTransferObjects/Tracks/CreateTrackRequest.cs b/WebApi/DataTransferObjects/Tracks/CreateTrackRequest.cs new file mode 100644 index 0000000..cedac41 --- /dev/null +++ b/WebApi/DataTransferObjects/Tracks/CreateTrackRequest.cs @@ -0,0 +1,6 @@ +namespace WebApi.DataTransferObjects.Tracks; + +public record CreateTrackRequest( + string Title, + Guid PictureIntentId, + Guid AudioIntentId); diff --git a/WebApi/DataTransferObjects/Tracks/RequestTrackUploadUrlsRequest.cs b/WebApi/DataTransferObjects/Tracks/RequestTrackUploadUrlsRequest.cs new file mode 100644 index 0000000..64144a6 --- /dev/null +++ b/WebApi/DataTransferObjects/Tracks/RequestTrackUploadUrlsRequest.cs @@ -0,0 +1,9 @@ +namespace WebApi.DataTransferObjects.Tracks; + +public record RequestTrackUploadUrlsRequest( + string PictureFileType, + string PictureContentType, + string AudioFileType, + string AudioContentType, + long? ExpectedPictureSizeBytes = null, + long? ExpectedAudioSizeBytes = null); diff --git a/WebApi/DataTransferObjects/Users/CreateUserRequest.cs b/WebApi/DataTransferObjects/Users/CreateUserRequest.cs new file mode 100644 index 0000000..5937975 --- /dev/null +++ b/WebApi/DataTransferObjects/Users/CreateUserRequest.cs @@ -0,0 +1,7 @@ +namespace WebApi.DataTransferObjects.Users; + +public record CreateUserRequest( + Guid Id, + string Name, + string? FirstName, + string? SecondName); diff --git a/WebApi/Endpoints/PlayListEndpoints.cs b/WebApi/Endpoints/PlayListEndpoints.cs new file mode 100644 index 0000000..b58e981 --- /dev/null +++ b/WebApi/Endpoints/PlayListEndpoints.cs @@ -0,0 +1,130 @@ +using Mediator; +using Musify.Application.PlayLists.Commands; +using Musify.Application.PlayLists.Queries; +using WebApi.DataTransferObjects.PlayLists; +using WebApi.Extensions; + +namespace WebApi.Endpoints; + +public static class PlayListEndpoints +{ + public static IEndpointRouteBuilder MapPlayListEndpoints(this IEndpointRouteBuilder app) + { + var group = app.MapGroup("/api/playlists") + .WithTags("PlayLists"); + + group.MapGet("/", GetPlayLists) + .WithName("GetPlayLists") + .WithSummary("Get paginated playlists."); + + group.MapGet("/{id:guid}", GetPlayListById) + .WithName("GetPlayListById") + .WithSummary("Get a playlist by ID."); + + group.MapGet("/users/{userId:guid}", GetPlayListsByUserId) + .WithName("GetPlayListsByUserId") + .WithSummary("Get paginated playlists for a user."); + + group.MapPost("/users/{userId:guid}", CreatePlayList) + .WithName("CreatePlayList") + .WithSummary("Create a new playlist."); + + group.MapPut("/{playlistId:guid}/users/{userId:guid}", UpdatePlayList) + .WithName("UpdatePlayList") + .WithSummary("Update an existing playlist."); + + group.MapDelete("/{playlistId:guid}/users/{userId:guid}", DeletePlayList) + .WithName("DeletePlayList") + .WithSummary("Delete a playlist."); + + group.MapPost("/upload-picture/users/{userId:guid}", RequestPlayListPictureUpload) + .WithName("RequestPlayListPictureUpload") + .WithSummary("Request a pre-signed URL to upload a playlist picture."); + + return app; + } + + private static async Task GetPlayLists( + IMediator mediator, + int pageNumber = 1, + int pageSize = 10, + CancellationToken ct = default) + { + var result = await mediator.Send(new GetPlayListsQuery(pageNumber, pageSize), ct); + return result.ToHttpResult(); + } + + private static async Task GetPlayListById( + IMediator mediator, + Guid id, + CancellationToken ct) + { + var result = await mediator.Send(new GetPlayListByIdQuery(id), ct); + return result.ToHttpResult(); + } + + private static async Task GetPlayListsByUserId( + IMediator mediator, + Guid userId, + string? name, + int pageNumber = 1, + int pageSize = 10, + CancellationToken ct = default) + { + var result = await mediator.Send(new GetPlayListsByUserIdQuery(userId, name, pageNumber, pageSize), ct); + return result.ToHttpResult(); + } + + private static async Task CreatePlayList( + IMediator mediator, + Guid userId, + CreatePlayListRequest request, + CancellationToken ct) + { + var result = await mediator.Send( + new CreatePlayListCommand(userId, request.Name, request.Description, request.PictureIntentId), + ct); + + if (!result.IsSuccess) + return result.ToHttpResult(); + + return Results.Created($"/api/playlists/{result.Value.Id}", result.Value); + } + + private static async Task UpdatePlayList( + IMediator mediator, + Guid userId, + Guid playlistId, + UpdatePlayListRequest request, + CancellationToken ct) + { + var result = await mediator.Send( + new UpdatePlayListCommand(userId, playlistId, request.NewName, request.NewDescription, request.NewPictureIntentId), + ct); + + return result.ToHttpResult(); + } + + private static async Task DeletePlayList( + IMediator mediator, + Guid userId, + Guid playlistId, + CancellationToken ct) + { + var result = await mediator.Send(new DeletePlayListCommand(userId, playlistId), ct); + return result.ToHttpResult(); + } + + private static async Task RequestPlayListPictureUpload( + IMediator mediator, + Guid userId, + RequestPlayListPictureUploadRequest request, + CancellationToken ct) + { + var result = await mediator.Send( + new RequestPlayListPictureUploadCommand(userId, request.FileType, request.ContentType, request.ExpectedSizeBytes), + ct); + + return result.ToHttpResult(); + } +} diff --git a/WebApi/Endpoints/TrackEndpoints.cs b/WebApi/Endpoints/TrackEndpoints.cs new file mode 100644 index 0000000..d576341 --- /dev/null +++ b/WebApi/Endpoints/TrackEndpoints.cs @@ -0,0 +1,119 @@ +using Mediator; +using Musify.Application.Tracks.Commands; +using Musify.Application.Tracks.Queries; +using WebApi.DataTransferObjects.Tracks; +using WebApi.Extensions; + +namespace WebApi.Endpoints; + +public static class TrackEndpoints +{ + public static IEndpointRouteBuilder MapTrackEndpoints(this IEndpointRouteBuilder app) + { + var group = app.MapGroup("/api/tracks") + .WithTags("Tracks"); + + group.MapGet("/", GetTracks) + .WithName("GetTracks") + .WithSummary("Get paginated tracks."); + + group.MapGet("/{id:guid}", GetTrackById) + .WithName("GetTrackById") + .WithSummary("Get a track by ID."); + + group.MapGet("/users/{userId:guid}", GetTracksByUserId) + .WithName("GetTracksByUserId") + .WithSummary("Get paginated tracks for a user."); + + group.MapPost("/users/{userId:guid}", CreateTrack) + .WithName("CreateTrack") + .WithSummary("Create a new track."); + + group.MapDelete("/{trackId:guid}/users/{userId:guid}", DeleteTrack) + .WithName("DeleteTrack") + .WithSummary("Delete a track."); + + group.MapPost("/upload-urls/users/{userId:guid}", RequestTrackUploadUrls) + .WithName("RequestTrackUploadUrls") + .WithSummary("Request pre-signed URLs to upload track picture and audio."); + + return app; + } + + private static async Task GetTracks( + IMediator mediator, + int pageNumber = 1, + int pageSize = 10, + CancellationToken ct = default) + { + var result = await mediator.Send(new GetTracksQuery(pageNumber, pageSize), ct); + return result.ToHttpResult(); + } + + private static async Task GetTrackById( + IMediator mediator, + Guid id, + CancellationToken ct) + { + var result = await mediator.Send(new GetTrackByIdQuery(id), ct); + return result.ToHttpResult(); + } + + private static async Task GetTracksByUserId( + IMediator mediator, + Guid userId, + string? name, + int pageNumber = 1, + int pageSize = 10, + CancellationToken ct = default) + { + var result = await mediator.Send(new GetTracksByUserIdQuery(userId, name, pageNumber, pageSize), ct); + return result.ToHttpResult(); + } + + private static async Task CreateTrack( + IMediator mediator, + Guid userId, + CreateTrackRequest request, + CancellationToken ct) + { + var result = await mediator.Send( + new CreateTrackCommand(userId, request.Title, request.PictureIntentId, request.AudioIntentId), + ct); + + if (!result.IsSuccess) + return result.ToHttpResult(); + + return Results.Created($"/api/tracks/{result.Value.Id}", result.Value); + } + + private static async Task DeleteTrack( + IMediator mediator, + Guid userId, + Guid trackId, + CancellationToken ct) + { + var result = await mediator.Send(new DeleteTrackCommand(userId, trackId), ct); + return result.ToHttpResult(); + } + + private static async Task RequestTrackUploadUrls( + IMediator mediator, + Guid userId, + RequestTrackUploadUrlsRequest request, + CancellationToken ct) + { + var result = await mediator.Send( + new RequestTrackUploadUrlsCommand( + userId, + request.PictureFileType, + request.PictureContentType, + request.AudioFileType, + request.AudioContentType, + request.ExpectedPictureSizeBytes, + request.ExpectedAudioSizeBytes), + ct); + + return result.ToHttpResult(); + } +} diff --git a/WebApi/Endpoints/UserEndpoints.cs b/WebApi/Endpoints/UserEndpoints.cs new file mode 100644 index 0000000..099d961 --- /dev/null +++ b/WebApi/Endpoints/UserEndpoints.cs @@ -0,0 +1,78 @@ +using Mediator; +using Musify.Application.Users.Commands; +using Musify.Application.Users.Queries; +using WebApi.DataTransferObjects.Users; +using WebApi.Extensions; + +namespace WebApi.Endpoints; + +public static class UserEndpoints +{ + public static IEndpointRouteBuilder MapUserEndpoints(this IEndpointRouteBuilder app) + { + var group = app.MapGroup("/api/users") + .WithTags("Users"); + + group.MapGet("/", GetUsers) + .WithName("GetUsers") + .WithSummary("Get paginated users."); + + group.MapGet("/{id:guid}", GetUserById) + .WithName("GetUserById") + .WithSummary("Get a user by ID."); + + group.MapGet("/keycloak/{id:guid}", GetUserByKeycloak) + .WithName("GetUserByKeycloak") + .WithSummary("Get a user by Keycloak ID."); + + group.MapPost("/", CreateUser) + .WithName("CreateUser") + .WithSummary("Create a new user."); + + return app; + } + + private static async Task GetUsers( + IMediator mediator, + int pageNumber = 1, + int pageSize = 10, + string? usernameSearch = null, + CancellationToken ct = default) + { + var result = await mediator.Send(new GetUsersQuery(pageNumber, pageSize, usernameSearch), ct); + return result.ToHttpResult(); + } + + private static async Task GetUserById( + IMediator mediator, + Guid id, + CancellationToken ct) + { + var result = await mediator.Send(new GetUserByIdQuery(id), ct); + return result.ToHttpResult(); + } + + private static async Task GetUserByKeycloak( + IMediator mediator, + Guid id, + CancellationToken ct) + { + var result = await mediator.Send(new GetUserByKeycloakQuery(id), ct); + return result.ToHttpResult(); + } + + private static async Task CreateUser( + IMediator mediator, + CreateUserRequest request, + CancellationToken ct) + { + var result = await mediator.Send( + new CreateUserCommand(request.Id, request.Name, request.FirstName, request.SecondName), + ct); + + if (!result.IsSuccess) + return result.ToHttpResult(); + + return Results.Created($"/api/users/{result.Value.Id}", result.Value); + } +} diff --git a/WebApi/Extensions/ResultHttpExtensions.cs b/WebApi/Extensions/ResultHttpExtensions.cs new file mode 100644 index 0000000..7b8a939 --- /dev/null +++ b/WebApi/Extensions/ResultHttpExtensions.cs @@ -0,0 +1,35 @@ +using Ardalis.Result; + +namespace WebApi.Extensions; + +public static class ResultHttpExtensions +{ + public static IResult ToHttpResult(this Result result) => + result.Status switch + { + ResultStatus.Ok or ResultStatus.NoContent => Results.NoContent(), + ResultStatus.NotFound => Results.NotFound(result.Errors.FirstOrDefault()), + ResultStatus.Invalid => Results.ValidationProblem(ToValidationDictionary(result.ValidationErrors)), + ResultStatus.Unauthorized => Results.Unauthorized(), + ResultStatus.Forbidden => Results.StatusCode(StatusCodes.Status403Forbidden), + ResultStatus.Conflict => Results.Conflict(result.Errors.FirstOrDefault()), + _ => Results.Problem(string.Join(", ", result.Errors)) + }; + + public static IResult ToHttpResult(this Result result) => + result.Status switch + { + ResultStatus.Ok => Results.Ok(result.Value), + ResultStatus.NotFound => Results.NotFound(result.Errors.FirstOrDefault()), + ResultStatus.Invalid => Results.ValidationProblem(ToValidationDictionary(result.ValidationErrors)), + ResultStatus.Unauthorized => Results.Unauthorized(), + ResultStatus.Forbidden => Results.StatusCode(StatusCodes.Status403Forbidden), + ResultStatus.Conflict => Results.Conflict(result.Errors.FirstOrDefault()), + _ => Results.Problem(string.Join(", ", result.Errors)) + }; + + private static Dictionary ToValidationDictionary(IEnumerable errors) => + errors + .GroupBy(e => e.Identifier) + .ToDictionary(g => g.Key, g => g.Select(e => e.ErrorMessage).ToArray()); +} diff --git a/WebApi/Extensions/ServiceCollectionExtensions.cs b/WebApi/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..e4fd603 --- /dev/null +++ b/WebApi/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,50 @@ +using Mediator; +using Musify.Application; +using Musify.Infrastructure.MassTransit; +using Musify.Infrastructure.Persistence; +using Musify.Infrastructure.Services; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; +using WebApi.Options; + +namespace WebApi.Extensions; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddApplicationConfigurations(configuration); + services.AddDatabase(configuration); + services.AddKeycloakService(configuration); + services.AddStorageService(configuration); + services.AddMassTransitClient(configuration); + services.AddMediator(); + services.AddOpenApi(); + + return services; + } + + public static IServiceCollection AddObservability(this IServiceCollection services, IConfiguration configuration) + { + var otlpEndpoint = new Uri(configuration + .GetRequiredSection(OpenTelemetryOptions.SectionName) + .GetRequiredSection(nameof(OpenTelemetryOptions.OtlpEndpoint)) + .Value!); + + services.AddOpenTelemetry() + .WithTracing(tracing => tracing + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddOtlpExporter(o => o.Endpoint = otlpEndpoint)) + .WithMetrics(metrics => metrics + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddOtlpExporter(o => o.Endpoint = otlpEndpoint)); + + services.Configure(logging => + logging.AddOtlpExporter(o => o.Endpoint = otlpEndpoint)); + + return services; + } +} diff --git a/WebApi/Options/OpenTelemetryOptions.cs b/WebApi/Options/OpenTelemetryOptions.cs new file mode 100644 index 0000000..938e30a --- /dev/null +++ b/WebApi/Options/OpenTelemetryOptions.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace WebApi.Options; + +public sealed class OpenTelemetryOptions +{ + public const string SectionName = "OpenTelemetry"; + + [Required] + public string OtlpEndpoint { get; init; } = string.Empty; +} diff --git a/WebApi/Program.cs b/WebApi/Program.cs new file mode 100644 index 0000000..d52c69b --- /dev/null +++ b/WebApi/Program.cs @@ -0,0 +1,24 @@ +using Scalar.AspNetCore; +using WebApi.Endpoints; +using WebApi.Extensions; + +var builder = WebApplication.CreateBuilder(); + +builder.Services + .AddApplicationServices(builder.Configuration) + .AddObservability(builder.Configuration); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); + app.MapScalarApiReference(); +} + +app + .MapPlayListEndpoints() + .MapTrackEndpoints() + .MapUserEndpoints(); + +app.Run(); diff --git a/WebApi/Properties/launchSettings.json b/WebApi/Properties/launchSettings.json new file mode 100644 index 0000000..a96b644 --- /dev/null +++ b/WebApi/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5111", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WebApi/WebApi.csproj b/WebApi/WebApi.csproj new file mode 100644 index 0000000..dc08b91 --- /dev/null +++ b/WebApi/WebApi.csproj @@ -0,0 +1,44 @@ + + + + net10.0 + enable + enable + 1c3fa41c-6f07-433b-af79-1f67fad338fd + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\MusifyBackend\Infrastructure\bin\Debug\net10.0\Application.dll + + + ..\..\MusifyBackend\Infrastructure\bin\Debug\net10.0\Domain.dll + + + ..\..\MusifyBackend\Infrastructure\bin\Debug\net10.0\Infrastructure.dll + + + + diff --git a/WebApi/WebApi.http b/WebApi/WebApi.http new file mode 100644 index 0000000..213749e --- /dev/null +++ b/WebApi/WebApi.http @@ -0,0 +1,6 @@ +@WebApi_HostAddress = http://localhost:5111 + +GET {{WebApi_HostAddress}}/weatherforecast/ +Accept: application/json + +###