|
1 | | -# 🧪 Web API made with .NET 8 (LTS) and ASP.NET Core |
2 | | - |
3 | | -## Status |
| 1 | +# 🧪 RESTful API with .NET and ASP.NET Core |
4 | 2 |
|
5 | 3 | [](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet.yml) |
6 | 4 | [](https://sonarcloud.io/summary/new_code?id=nanotaboada_Dotnet.Samples.AspNetCore.WebApi) |
7 | 5 | [](https://dev.azure.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/_build/latest?definitionId=14&branchName=master) |
8 | 6 | [](https://app.codacy.com/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) |
9 | 7 | [](https://codecov.io/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi) |
10 | 8 | [](https://www.codefactor.io/repository/github/nanotaboada/Dotnet.Samples.AspNetCore.WebApi) |
| 9 | +[](https://opensource.org/licenses/MIT) |
11 | 10 |
|
12 | | -## About |
| 11 | +Proof of Concept for a RESTful API built with .NET 8 (LTS) and ASP.NET Core. Manage football player data with SQLite, Entity Framework Core, Swagger documentation, and in-memory caching. |
13 | 12 |
|
14 | | -Proof of Concept for a Web API made with [.NET 8](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8) (LTS) and [ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-8.0?view=aspnetcore-8.0). |
| 13 | +## Table of Contents |
15 | 14 |
|
16 | | -## Structure |
| 15 | +- [Features](#features) |
| 16 | +- [Tech Stack](#tech-stack) |
| 17 | +- [Project Structure](#project-structure) |
| 18 | +- [Architecture](#architecture) |
| 19 | +- [API Reference](#api-reference) |
| 20 | +- [Prerequisites](#prerequisites) |
| 21 | +- [Quick Start](#quick-start) |
| 22 | +- [Testing](#testing) |
| 23 | +- [Docker](#docker) |
| 24 | +- [Environment Variables](#environment-variables) |
| 25 | +- [Command Summary](#command-summary) |
| 26 | +- [Contributing](#contributing) |
| 27 | +- [Legal](#legal) |
17 | 28 |
|
18 | | - |
| 29 | +## Features |
19 | 30 |
|
20 | | -_Figure: Simplified, conceptual project structure and main application flow. Not all dependencies are shown._ |
| 31 | +- 🔌 RESTful CRUD operations for football player data |
| 32 | +- 📚 Interactive API documentation |
| 33 | +- 🚦 Fixed window rate limiting |
| 34 | +- ⌨️ Input validation |
| 35 | +- ⚡ In-memory caching (1-hour TTL) |
| 36 | +- 💿 Relational database with ORM |
| 37 | +- 🏗️ Layered architecture pattern |
| 38 | +- ⌛ Asynchronous operations throughout |
| 39 | +- 📝 Structured logging to console and file |
| 40 | +- 🩺 Health check endpoint for monitoring |
| 41 | +- 🐳 Full containerization support |
| 42 | +- ✅ Comprehensive unit tests |
21 | 43 |
|
22 | | -## Start |
| 44 | +## Tech Stack |
| 45 | + |
| 46 | +| Category | Technology | |
| 47 | +|----------|------------| |
| 48 | +| **Framework** | [.NET 8](https://github.com/dotnet/core) (LTS) | |
| 49 | +| **Web Framework** | [ASP.NET Core 8.0](https://github.com/dotnet/aspnetcore) | |
| 50 | +| **API Documentation** | [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) (OpenAPI 3.0) | |
| 51 | +| **Validation** | [FluentValidation 12](https://github.com/FluentValidation/FluentValidation) | |
| 52 | +| **Mapping** | [AutoMapper 14](https://github.com/AutoMapper/AutoMapper) | |
| 53 | +| **Database** | [SQLite 3](https://github.com/sqlite/sqlite) | |
| 54 | +| **ORM** | [Entity Framework Core 9.0](https://github.com/dotnet/efcore) | |
| 55 | +| **Logging** | [Serilog 9](https://github.com/serilog/serilog) | |
| 56 | +| **Testing** | [xUnit](https://github.com/xunit/xunit), [Moq](https://github.com/devlooped/moq), [FluentAssertions](https://github.com/fluentassertions/fluentassertions) | |
| 57 | +| **Containerization** | [Docker](https://github.com/docker) & [Docker Compose](https://github.com/docker/compose) | |
| 58 | + |
| 59 | +## Project Structure |
23 | 60 |
|
24 | | -```console |
25 | | -dotnet watch run --project src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj |
26 | 61 | ``` |
| 62 | +src/Dotnet.Samples.AspNetCore.WebApi/ |
| 63 | +├── Program.cs # Entry point: DI setup, middleware pipeline |
| 64 | +├── Controllers/ # HTTP handlers (request/response logic) |
| 65 | +│ └── PlayerController.cs |
| 66 | +├── Services/ # Business logic + caching layer |
| 67 | +│ ├── IPlayerService.cs |
| 68 | +│ └── PlayerService.cs |
| 69 | +├── Repositories/ # Data access abstraction |
| 70 | +│ ├── IPlayerRepository.cs |
| 71 | +│ ├── IRepository.cs |
| 72 | +│ ├── PlayerRepository.cs |
| 73 | +│ └── Repository.cs |
| 74 | +├── Models/ # Domain entities and DTOs |
| 75 | +│ ├── Player.cs |
| 76 | +│ ├── PlayerRequestModel.cs |
| 77 | +│ └── PlayerResponseModel.cs |
| 78 | +├── Data/ # EF Core DbContext |
| 79 | +│ └── PlayerDbContext.cs |
| 80 | +├── Mappings/ # AutoMapper profiles |
| 81 | +│ └── PlayerMappingProfile.cs |
| 82 | +├── Validators/ # FluentValidation rules |
| 83 | +│ └── PlayerRequestModelValidator.cs |
| 84 | +├── Configurations/ # Swagger, rate limiting config |
| 85 | +├── Extensions/ # Service registration extensions |
| 86 | +├── Utilities/ # Helper classes |
| 87 | +├── Migrations/ # EF Core migrations |
| 88 | +└── storage/ # Pre-seeded SQLite database |
| 89 | +
|
| 90 | +test/Dotnet.Samples.AspNetCore.WebApi.Tests/ |
| 91 | +└── Unit/ # Unit tests with xUnit |
| 92 | + ├── PlayerControllerTests.cs |
| 93 | + └── PlayerServiceTests.cs |
| 94 | +``` |
| 95 | + |
| 96 | +## Architecture |
| 97 | + |
| 98 | +Dependencies flow from data layer through repositories and services to controllers. External dependencies (AutoMapper, FluentValidation, Serilog) integrate at their respective layers. |
27 | 99 |
|
28 | | -## Documentation (Development-only) |
| 100 | +```mermaid |
| 101 | +%%{init: {'theme':'base'}}%% |
| 102 | +graph TD |
| 103 | + Data[Data]:::core --> Models[Models]:::core |
| 104 | + Models --> Repositories[Repositories]:::core |
| 105 | + Repositories --> Services[Services]:::core |
| 106 | + Services --> Controllers[Controllers]:::core |
| 107 | + Controllers --> Program[Program]:::core |
29 | 108 |
|
30 | | -```console |
31 | | -https://localhost:9000/swagger/index.html |
| 109 | + Validators[Validators]:::core --> Controllers |
| 110 | + Mappings[Mappings]:::core --> Services |
| 111 | +
|
| 112 | + AutoMapper[AutoMapper]:::external --> Mappings |
| 113 | + FluentValidation[FluentValidation]:::external --> Validators |
| 114 | + Serilog[Serilog]:::external --> Program |
| 115 | +
|
| 116 | + Configurations[Configurations]:::infrastructure --> Program |
| 117 | + SwaggerUI[SwaggerUI]:::infrastructure --> Controllers |
| 118 | + MemoryCache[MemoryCache]:::infrastructure --> Services |
| 119 | + Migrations[Migrations]:::infrastructure --> Repositories |
| 120 | +
|
| 121 | + Controllers --> Tests[Tests]:::testing |
| 122 | + Services --> Tests |
| 123 | +
|
| 124 | + classDef core fill:#cfe4ff,stroke:#333333,stroke-width:2px,color:#000 |
| 125 | + classDef external fill:#ffd9d9,stroke:#333333,stroke-width:2px,color:#000 |
| 126 | + classDef infrastructure fill:#fcfcca,stroke:#333333,stroke-width:2px,color:#000 |
| 127 | + classDef testing fill:#c3f7c8,stroke:#333333,stroke-width:2px,color:#000 |
32 | 128 | ``` |
33 | 129 |
|
34 | | - |
| 130 | +*Layered architecture: Core application flow (blue), supporting features (yellow), external dependencies (red), and test coverage (green). Not all dependencies are shown.* |
| 131 | + |
| 132 | +## API Reference |
| 133 | + |
| 134 | +Interactive API documentation is available via Swagger UI at `https://localhost:9000/swagger/index.html` when the server is running. |
| 135 | + |
| 136 | +> 💡 **Note:** Swagger documentation is only available in development mode for security reasons. |
| 137 | +
|
| 138 | +**Quick Reference:** |
35 | 139 |
|
36 | | -## Container |
| 140 | +- `GET /players` - List all players |
| 141 | +- `GET /players/{id}` - Get player by ID (requires authentication) |
| 142 | +- `GET /players/squad/{squadNumber}` - Get player by squad number |
| 143 | +- `POST /players` - Create new player |
| 144 | +- `PUT /players/{squadNumber}` - Update player |
| 145 | +- `DELETE /players/{squadNumber}` - Remove player |
| 146 | +- `GET /health` - Health check |
37 | 147 |
|
38 | | -### Docker Compose |
| 148 | +For complete endpoint documentation with request/response schemas, explore the [interactive Swagger UI](https://localhost:9000/swagger/index.html). |
39 | 149 |
|
40 | | -This setup uses [Docker Compose](https://docs.docker.com/compose/) to build and run the app and manage a persistent SQLite database stored in a Docker volume. |
| 150 | +## Prerequisites |
41 | 151 |
|
42 | | -#### Build the image |
| 152 | +Before you begin, ensure you have the following installed: |
| 153 | + |
| 154 | +- .NET 8 SDK (LTS) or higher |
| 155 | +- Docker Desktop (optional, for containerized deployment) |
| 156 | +- dotnet-ef CLI tool (for database migrations) |
| 157 | + |
| 158 | + ```bash |
| 159 | + dotnet tool install --global dotnet-ef |
| 160 | + ``` |
| 161 | + |
| 162 | +## Quick Start |
| 163 | + |
| 164 | +### Clone the repository |
| 165 | + |
| 166 | +```bash |
| 167 | +git clone https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi.git |
| 168 | +cd Dotnet.Samples.AspNetCore.WebApi |
| 169 | +``` |
| 170 | + |
| 171 | +### Run the application |
| 172 | + |
| 173 | +```bash |
| 174 | +dotnet watch run --project src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj |
| 175 | +``` |
| 176 | + |
| 177 | +The server will start on `https://localhost:9000`. |
| 178 | + |
| 179 | +### Access the application |
| 180 | + |
| 181 | +- API: `https://localhost:9000` |
| 182 | +- Swagger Documentation: `https://localhost:9000/swagger/index.html` |
| 183 | +- Health Check: `https://localhost:9000/health` |
| 184 | + |
| 185 | +## Testing |
| 186 | + |
| 187 | +Run the test suite with xUnit: |
| 188 | + |
| 189 | +```bash |
| 190 | +# Run all tests |
| 191 | +dotnet test |
| 192 | + |
| 193 | +# Run tests with coverage report |
| 194 | +dotnet test --results-directory "coverage" --collect:"XPlat Code Coverage" --settings .runsettings |
| 195 | + |
| 196 | +# View coverage report |
| 197 | +dotnet tool install --global dotnet-reportgenerator-globaltool |
| 198 | +reportgenerator -reports:coverage/**/coverage.cobertura.xml -targetdir:coverage -reporttypes:Html |
| 199 | +``` |
| 200 | + |
| 201 | +Tests are located in the `test/` directory and use xUnit for unit testing. Coverage reports are generated for controllers and services only. |
| 202 | + |
| 203 | +## Docker |
| 204 | + |
| 205 | +This project includes full Docker support with multi-stage builds and Docker Compose for easy deployment. |
| 206 | + |
| 207 | +### Build the Docker image |
43 | 208 |
|
44 | 209 | ```bash |
45 | 210 | docker compose build |
46 | 211 | ``` |
47 | 212 |
|
48 | | -#### Start the app |
| 213 | +### Start the application |
49 | 214 |
|
50 | 215 | ```bash |
51 | 216 | docker compose up |
52 | 217 | ``` |
53 | 218 |
|
54 | | -> On first run, the container copies a pre-seeded SQLite database into a persistent volume |
55 | | -> On subsequent runs, that volume is reused and the data is preserved |
| 219 | +> 💡 **Note:** On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved. |
56 | 220 |
|
57 | | -#### Stop the app |
| 221 | +### Stop the application |
58 | 222 |
|
59 | 223 | ```bash |
60 | 224 | docker compose down |
61 | 225 | ``` |
62 | 226 |
|
63 | | -#### Optional: database reset |
| 227 | +### Reset the database |
| 228 | + |
| 229 | +To remove the volume and reinitialize the database from the built-in seed file: |
64 | 230 |
|
65 | 231 | ```bash |
66 | 232 | docker compose down -v |
67 | 233 | ``` |
68 | 234 |
|
69 | | -> This removes the volume and will reinitialize the database from the built-in seed file the next time you `up`. |
| 235 | +The containerized application runs on port 9000 and includes health checks that monitor the `/health` endpoint. |
| 236 | + |
| 237 | +## Environment Variables |
| 238 | + |
| 239 | +The application can be configured using environment variables for different scenarios: |
| 240 | + |
| 241 | +### Local Development (`.vscode/launch.json`) |
| 242 | + |
| 243 | +For local debugging and development: |
| 244 | + |
| 245 | +```bash |
| 246 | +# ASP.NET Core environment mode |
| 247 | +ASPNETCORE_ENVIRONMENT=Development |
| 248 | + |
| 249 | +# Server URLs |
| 250 | +ASPNETCORE_URLS=https://localhost:9000 |
| 251 | + |
| 252 | +# Show detailed error messages |
| 253 | +ASPNETCORE_DETAILEDERRORS=1 |
| 254 | + |
| 255 | +# Graceful shutdown timeout |
| 256 | +ASPNETCORE_SHUTDOWNTIMEOUTSECONDS=3 |
| 257 | +``` |
| 258 | + |
| 259 | +### Docker Deployment (`compose.yaml`) |
| 260 | + |
| 261 | +For containerized production deployment: |
| 262 | + |
| 263 | +```bash |
| 264 | +# Database storage path |
| 265 | +# Points to the persistent Docker volume |
| 266 | +STORAGE_PATH=/storage/players-sqlite3.db |
| 267 | +``` |
| 268 | + |
| 269 | +> 💡 **Note:** Additional environment variables (`ASPNETCORE_ENVIRONMENT=Production` and `ASPNETCORE_URLS=http://+:9000`) are set in the `Dockerfile`. |
| 270 | +
|
| 271 | +## Command Summary |
| 272 | + |
| 273 | +| Command | Description | |
| 274 | +|---------|-------------| |
| 275 | +| `dotnet watch run --project src/...` | Start development server with hot reload | |
| 276 | +| `dotnet build` | Build the solution | |
| 277 | +| `dotnet test` | Run all tests | |
| 278 | +| `dotnet test --collect:"XPlat Code Coverage"` | Run tests with coverage report | |
| 279 | +| `dotnet ef migrations add <Name>` | Create a new migration | |
| 280 | +| `dotnet ef database update` | Apply migrations | |
| 281 | +| `./scripts/run-migrations-and-copy-database.sh` | Regenerate database with seed data | |
| 282 | +| `docker compose build` | Build Docker image | |
| 283 | +| `docker compose up` | Start Docker container | |
| 284 | +| `docker compose down` | Stop Docker container | |
| 285 | +| `docker compose down -v` | Stop and remove Docker volume | |
| 286 | + |
| 287 | +## Contributing |
| 288 | + |
| 289 | +Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduct and the process for submitting pull requests. |
70 | 290 |
|
71 | | -## Credits |
| 291 | +**Key guidelines:** |
72 | 292 |
|
73 | | -The solution has been coded using [Visual Studio Code](https://code.visualstudio.com/) with the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension. |
| 293 | +- Follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages |
| 294 | +- Ensure all tests pass (`dotnet test`) |
| 295 | +- Keep changes small and focused |
| 296 | +- Review [.github/copilot-instructions.md](.github/copilot-instructions.md) for architectural patterns |
74 | 297 |
|
75 | | -## Terms |
| 298 | +## Legal |
76 | 299 |
|
77 | | -All trademarks, registered trademarks, service marks, product names, company names, or logos mentioned on this repository are the property of their respective owners. All usage of such terms herein is for identification purposes only and constitutes neither an endorsement nor a recommendation of those items. Furthermore, the use of such terms is intended to be for educational and informational purposes only. |
| 300 | +This is a proof-of-concept project intended for educational and demonstration purposes. All trademarks, registered trademarks, service marks, product names, company names, or logos mentioned are the property of their respective owners and are used for identification purposes only. |
0 commit comments