This repository serves as a proof of concept for writing a minimal web application that allows users to create and share playlists of songs.
The application is split into several projects:
LivePlaylist.Api
- Minimal API service that allows users to create and modify playlistsLivePlaylist.Common
- Common models and services used by the API and Web projectsLivePlaylist.Web
- Blazor Web Assembly app that acts as a front-end for the APILivePlaylist.Tests
- Unit tests for the API services
- .NET Core 7
- FluentValidation - Model validation
- FluentAssertions - Unit test assertions
- Swashbuckle.AspNetCore - Swagger documentation
- TailwindCSS - CSS framework & design system
The API project is structured as follows:
Auth/
- Contains authorization and authentication schemesData/
- Contains data parsers and initialization helpersEndpoints/
- Contains the API endpoints for the applicationExamples/
- Contains examples of accessing the API endpointsFilters/
- Contains the filters (middleware) used by endpointsModels/
- Contains the DTO models used by the API specificallyServices/
- Contains the services used by the applicationValidators/
- Contains the validators used by the applicationProgram.cs
- Entry point for the application that configures the API
Services are injected using the built-in dependency injection container IServiceCollection
.
This is commonly used in .NET Core applications and allows for easy testing and mocking of services.
To run the API, you can use the following command:
cd LivePlaylist.Api
dotnet run
This will start the API on http://localhost:3000.
The API documentation is automatically generated using Swagger.
You can access the documentation by running the API and navigating to http://localhost:3000/swagger/index.html.
To run the unit tests, you can use the following command:
dotnet test -l "console;verbosity=normal"
The API uses a very basic "API Key" authentication scheme to simplify the proof of concept:
Authorization: User {username}
There are no passwords or special JWTs, just a simple username that is used to identify the user making the request.
Obviously this is not secure and would need to be replaced with an actual authentication scheme in a production application.
The API endpoints generally follow this flow:
[Request] -> Auth -> Filters -> Endpoint -> Service -> Data -> [Response]
Filters are optional middleware that can be applied to endpoints to perform additional validation or logging.
The API will automatically seed the in-memory data store with some initial data on startup:
- A default user named
admin
- Over 250 songs from the
songs.csv
file
This can be modified in the DataInitializer
class in the InitializeAsync
method.
The EndpointsExtensions
class extension methods that allow automatic service and endpoint registration
for all classes that implement the IEndpoints
interface within the assembly.
This is called in the Program.cs
file to register all endpoints without the need to manually register each one.
This helps promote the Open/Closed principle by allowing new endpoints to be added without
having to modify the Program.cs
file.
The web UI is a Blazor Web Assembly project and structured as follows:
wwwroot/
- Contains static files for HTML, CSS, and JavaScriptPages/
- Contains the Blazor pagesShared/
- Contains shared Blazor componentsStyles/
- Contains the TailwindCSS style definitionsMainLayout.razor
- The main layout used by all pagesProgram.cs
- Entry point for the application that configures the Blazor app
To run the web UI, you can use the following command:
cd LivePlaylist.Web
dotnet run
This will start the web UI on http://localhost:3001.
As of .NET 6, hot-reloading is enabled by default for Blazor Web Assembly projects:
cd LivePlaylist.Web
dotnet watch
This will automatically recompile and reload the web UI when changes are made.
The TailwindCSS styles are generated using the TailwindCSS
CLI tool:
cd LivePlaylist.Web
npx tailwindcss -i ./Styles/app.css -o ./wwwroot/css/app.css --watch
This will automatically recompile the TailwindCSS styles when changes are made, and works well with hot-reloading.