This project is a REST API built with ASP.NET Core (.NET 9) using Minimal API.
It includes:
- Layered architecture (API, Services, Domain, Data)
- EF Core Code First with PostgreSQL
- Seed data
- Database-backed users with hashed passwords
- Global exception handling middleware instead of try/catch blocks in each endpoint
- JWT authentication and role-based authorization
- Swagger/OpenAPI and Postman collection with scripts
API/-Endpoints.cs,DTO.csData/-AppDbContext.cs,Entities/,Repositories/Domain/-Models/,Repositories/Services/- business logicExceptions/-ApiExceptions.csMigrations/- EF Core migrations
- Have .NET 9 SDK and Docker installed.
- Have Postman installed for API testing and Swagger exploration.
- Optional: Have DataGrip installed for database inspection.
- Place yourself in
MovieDatabaseApi/with the CMD (terminal) and run the following:
dotnet restore- Start PostgreSQL with Docker Compose
docker compose up -d- Apply migration
dotnet ef database update- Start the API
dotnet run- Connection string is configured in
appsettings.json - Seed data for genres/movies/reviews is configured in
Data/AppDbContext.cs(HasData()) - Seeded auth users (
admin,user) are created on startup inProgram.cs - Migration files are in
Migrations/
Token endpoint:
POST /api/auth/token
The token endpoint validates users from the users table.
Passwords are stored as hashes using PasswordHasher<TUser>.
Seeded users:
admin/admin123-> roleAdminuser/user123-> roleUser
Request body for admin token:
{
"username": "admin",
"password": "admin123"
}Request body for user token:
{
"username": "user",
"password": "user123"
}Admin-protected endpoints:
POST /api/moviesPUT /api/movies/{id}DELETE /api/movies/{id}POST /api/genres
Authenticated endpoint (User or Admin):
POST /api/movies/{movieId}/reviews
GET /api/moviesGET /api/movies/{id}POST /api/movies(Admin)PUT /api/movies/{id}(Admin)DELETE /api/movies/{id}(Admin)GET /api/genresPOST /api/genres(Admin)GET /api/movies/{movieId}/reviewsPOST /api/movies/{movieId}/reviews(User or Admin)POST /api/auth/token
Swagger URL:
http://localhost:5052/swagger
- Run the API
dotnet run - Open Swagger URL
- Use
POST /api/auth/token(with the admin request body above) to getaccess_tokenand copy it (without quotes) from the response body - Click Authorize in Swagger (should be in the top right corner) and paste your
access_tokenand close the popup window - Test protected endpoints (
POST/PUT/DELETE). You can now manually enter request bodies or use the "Try it out" feature in Swagger to send requests and see responses. - You can also test (with the user request body above) the user-protected endpoint (
POST /api/movies/{movieId}/reviews) by authenticating with the user credentials and repeating steps 3-5.
The JSON contract uses snake_case (for example, release_year and genre_id).
To ensure Swagger shows the same field names as the API, DTO fields in API/DTO.cs are annotated with JsonPropertyName.
Collection file:
postman/MovieDatabaseApi.postman_collection.json
How to use:
- Import collection in Postman
- Set collection variable
baseUrlto your running API URL (in this casehttp://localhost:5052) - Run from top to bottom in this order:
- Authenticate as Admin
- Authenticate as User
- Create Genre as Admin
- Create Movie as Admin
- Update Movie as Admin
- Create Review for Movie as User
- List Reviews for Movie
- Create Review for Movie (No Token)
- Delete Movie as Admin
- You can also right‑click the
MovieDatabaseApicollection and choose Run to execute the entire collection with the included test scripts.
Notes:
- Collection uses variables for token and created IDs
- Login is validated against seeded users in the database
- If a run fails, clear collection variables and run again from the first request
You can inspect PostgreSQL tables directly in DataGrip.
Connection values:
- Host:
localhost - Port:
5432 - Database/User/Password: from
docker-compose.ymland/or your connection string inappsettings.json
Setup with CMD (if you forgot to do that in the beginning):
docker compose up -d
dotnet ef database updateThen in DataGrip:
- Create a new PostgreSQL data source
- Enter host/port/database/user/password
- Connect and open tables:
genresmoviesreviewsusers
Quick SQL checks:
select * from genres;
select * from movies;
select * from reviews;
select username, role, created_at from users;Have fun!
Marcus Myran Inkerö
SYS25D
Signing out