{"id":49563363,"url":"https://github.com/rafiq15/aspnet-postgresql-crud-api","last_synced_at":"2026-05-03T10:47:37.496Z","repository":{"id":328316092,"uuid":"1115059030","full_name":"rafiq15/aspnet-postgresql-crud-api","owner":"rafiq15","description":"A clean ASP.NET Core 9.0 Web API demonstrating CRUD operations with PostgreSQL and Entity Framework Core. Features include RESTful endpoints, DTO pattern, data mapping, and Swagger documentation. Perfect as a starter template for building production-ready APIs.","archived":false,"fork":false,"pushed_at":"2026-01-02T12:20:35.000Z","size":11622,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-03T10:47:28.352Z","etag":null,"topics":["aspnet-core","async-await","crud","csharp","dotnet","dto-pattern","entity-framework-core","postgresql","rest-api","swagger","webapi"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rafiq15.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-12T09:28:52.000Z","updated_at":"2026-01-02T12:20:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rafiq15/aspnet-postgresql-crud-api","commit_stats":null,"previous_names":["rafiq15/aspnet-postgresql-crud-api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rafiq15/aspnet-postgresql-crud-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafiq15%2Faspnet-postgresql-crud-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafiq15%2Faspnet-postgresql-crud-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafiq15%2Faspnet-postgresql-crud-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafiq15%2Faspnet-postgresql-crud-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rafiq15","download_url":"https://codeload.github.com/rafiq15/aspnet-postgresql-crud-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafiq15%2Faspnet-postgresql-crud-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32566444,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnet-core","async-await","crud","csharp","dotnet","dto-pattern","entity-framework-core","postgresql","rest-api","swagger","webapi"],"created_at":"2026-05-03T10:47:36.871Z","updated_at":"2026-05-03T10:47:37.484Z","avatar_url":"https://github.com/rafiq15.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PgCrudApi - Product \u0026 User Management System\n\nASP.NET Core 9.0 Web API with JWT authentication, PostgreSQL database, and complete CRUD operations for products and user management. This project demonstrates modern API development with security, database migrations, and interactive API documentation using Swagger.\n\n## Features\n\n### Authentication \u0026 Authorization\n- ✅ JWT (JSON Web Token) authentication\n- ✅ User registration and login\n- ✅ Secure password hashing (SHA-256)\n- ✅ Protected endpoints with `[Authorize]` attribute\n- ✅ Token-based authentication in Swagger UI\n\n### Product Management\n- ✅ Full CRUD operations (Create, Read, Update, Delete)\n- ✅ RESTful API design\n- ✅ Protected endpoints requiring authentication\n- ✅ DTO pattern for data transfer\n- ✅ Entity mapping with custom mappers\n\n### User Management\n- ✅ User registration with email and username validation\n- ✅ User login with JWT token generation\n- ✅ Get all users (authenticated)\n- ✅ Get user by ID (authenticated)\n- ✅ Update user profile (authenticated)\n- ✅ Delete user (authenticated)\n- ✅ Duplicate email/username prevention\n\n### Technical Features\n- ✅ PostgreSQL database with Entity Framework Core\n- ✅ Async/await operations for better performance\n- ✅ Database migrations with EF Core\n- ✅ Swagger UI with JWT authentication support\n- ✅ CORS enabled for frontend integration\n- ✅ Custom Swagger operation filter for security\n- ✅ Proper error handling and validation\n\n## Tech Stack\n\n- **Framework:** ASP.NET Core 9.0\n- **Database:** PostgreSQL\n- **ORM:** Entity Framework Core 9.0\n- **Authentication:** JWT Bearer Token\n- **Language:** C# 12\n- **API Documentation:** Swagger/OpenAPI (Swashbuckle 7.2.0)\n\n### NuGet Packages\n- `Microsoft.AspNetCore.Authentication.JwtBearer` (9.0.0)\n- `Microsoft.AspNetCore.OpenApi` (9.0.10)\n- `Microsoft.EntityFrameworkCore.Design` (9.0.11)\n- `Npgsql.EntityFrameworkCore.PostgreSQL` (9.0.4)\n- `Swashbuckle.AspNetCore` (7.2.0)\n- `System.IdentityModel.Tokens.Jwt` (8.15.0)\n\n## Prerequisites\n\nBefore running this project, ensure you have:\n\n- [.NET 9.0 SDK](https://dotnet.microsoft.com/download/dotnet/9.0)\n- [PostgreSQL](https://www.postgresql.org/download/) (version 12 or higher)\n- A code editor (Visual Studio 2022, VS Code, or Rider)\n\n## Database Setup\n\n### 1. Configure Database Connection\n\nUpdate the connection string in `appsettings.json` if needed:\n\n```json\n{\n  \"ConnectionStrings\": {\n    \"DefaultConnection\": \"Host=localhost;Port=5432;Database=pgcruddb;Username=postgres;Password=root\"\n  }\n}\n```\n\n### 2. Configure JWT Settings\n\nThe JWT configuration is also in `appsettings.json`:\n\n```json\n{\n  \"Jwt\": {\n    \"Key\": \"YourSuperSecretKeyForJWTAuthenticationMinimum32Characters!\",\n    \"Issuer\": \"PgCrudApi\",\n    \"Audience\": \"PgCrudApiUsers\",\n    \"ExpireMinutes\": 60\n  }\n}\n```\n\n**Important:** Change the `Key` value to your own secret key in production!\n\n### 3. Apply Database Migrations\n\n```bash\ndotnet ef database update\n```\n\nThis will create the database and apply all migrations including:\n- `InitialCreate` - Creates the Products table\n- `AddUserTable` - Creates the Users table\n\n## Running the Application\n\n### Start the API\n\n```bash\ndotnet run\n```\n\nThe API will be available at:\n- **HTTP:** `http://localhost:5163`\n- **Swagger UI:** `http://localhost:5163/swagger/index.html`\n\n## Using Swagger UI\n\n1. Navigate to `http://localhost:5163/swagger/index.html`\n2. Test the authentication endpoints first (register/login)\n3. Copy the JWT token from the response\n4. Click the **Authorize** button at the top right\n5. Enter: `Bearer YOUR_JWT_TOKEN` (replace YOUR_JWT_TOKEN with the actual token)\n6. Click **Authorize**\n7. Now you can test all protected endpoints!\n\n## API Endpoints\n\n### Authentication Endpoints (Public)\n\n![Authentication Endpoints](images/swagger_auth.PNG)\n\n| Method | Endpoint | Description | Auth Required |\n|--------|----------|-------------|---------------|\n| POST | `/api/auth/register` | Register a new user | No |\n| POST | `/api/auth/login` | Login and get JWT token | No |\n\n### User Management Endpoints (Protected)\n\n| Method | Endpoint | Description | Auth Required |\n|--------|----------|-------------|---------------|\n| GET | `/api/auth/users` | Get all users | Yes |\n| GET | `/api/auth/users/{id}` | Get user by ID | Yes |\n| PUT | `/api/auth/users/{id}` | Update user profile | Yes |\n| DELETE | `/api/auth/users/{id}` | Delete user | Yes |\n\n### Product Endpoints (Protected)\n\n![Product Endpoints](images/swagger_product.PNG)\n\n| Method | Endpoint | Description | Auth Required |\n|--------|----------|-------------|---------------|\n| GET | `/api/products` | Get all products | Yes |\n| GET | `/api/products/{id}` | Get a product by ID | Yes |\n| POST | `/api/products` | Create a new product | Yes |\n| PUT | `/api/products/{id}` | Update an existing product | Yes |\n| DELETE | `/api/products/{id}` | Delete a product | Yes |\n\n## API Usage Examples\n\n### 1. Register a New User\n\n**Request:**\n```http\nPOST /api/auth/register\nContent-Type: application/json\n\n{\n  \"username\": \"johndoe\",\n  \"email\": \"john.doe@example.com\",\n  \"password\": \"SecurePassword123\"\n}\n```\n\n**Response (200 OK):**\n```json\n{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n  \"username\": \"johndoe\",\n  \"email\": \"john.doe@example.com\"\n}\n```\n\n### 2. Login\n\n**Request:**\n```http\nPOST /api/auth/login\nContent-Type: application/json\n\n{\n  \"email\": \"john.doe@example.com\",\n  \"password\": \"SecurePassword123\"\n}\n```\n\n**Response (200 OK):**\n```json\n{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n  \"username\": \"johndoe\",\n  \"email\": \"john.doe@example.com\"\n}\n```\n\n### 3. Get All Users (Protected)\n\n**Request:**\n```http\nGET /api/auth/users\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**Response (200 OK):**\n```json\n[\n  {\n    \"id\": 1,\n    \"username\": \"johndoe\",\n    \"email\": \"john.doe@example.com\",\n    \"createdAt\": \"2026-01-01T10:30:00Z\"\n  }\n]\n```\n\n### 4. Update User\n\n**Request:**\n```http\nPUT /api/auth/users/1\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\nContent-Type: application/json\n\n{\n  \"username\": \"john_updated\",\n  \"email\": \"john.updated@example.com\",\n  \"password\": \"NewPassword456\"\n}\n```\n\n**Response (200 OK):**\n```json\n{\n  \"id\": 1,\n  \"username\": \"john_updated\",\n  \"email\": \"john.updated@example.com\",\n  \"createdAt\": \"2026-01-01T10:30:00Z\"\n}\n```\n\n### 5. Create Product (Protected)\n\n**Request:**\n```http\nPOST /api/products\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\nContent-Type: application/json\n\n{\n  \"name\": \"Laptop\",\n  \"description\": \"High-performance laptop\",\n  \"price\": 999.99\n}\n```\n\n**Response (201 Created):**\n```json\n{\n  \"id\": 1,\n  \"name\": \"Laptop\",\n  \"description\": \"High-performance laptop\",\n  \"price\": 999.99,\n  \"createdAt\": \"2026-01-02T10:30:00Z\"\n}\n```\n\n### 6. Get All Products (Protected)\n\n**Request:**\n```http\nGET /api/products\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**Response (200 OK):**\n```json\n[\n  {\n    \"id\": 1,\n    \"name\": \"Laptop\",\n    \"description\": \"High-performance laptop\",\n    \"price\": 999.99,\n    \"createdAt\": \"2026-01-02T10:30:00Z\"\n  },\n  {\n    \"id\": 2,\n    \"name\": \"Mouse\",\n    \"description\": \"Wireless mouse\",\n    \"price\": 29.99,\n    \"createdAt\": \"2026-01-02T11:00:00Z\"\n  }\n]\n```\n\n### 7. Update Product (Protected)\n\n**Request:**\n```http\nPUT /api/products/1\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\nContent-Type: application/json\n\n{\n  \"name\": \"Gaming Laptop\",\n  \"description\": \"High-performance gaming laptop with RTX 4090\",\n  \"price\": 1299.99\n}\n```\n\n**Response:**\n```\n204 No Content\n```\n\n### 8. Delete Product (Protected)\n\n**Request:**\n```http\nDELETE /api/products/1\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**Response:**\n```\n204 No Content\n```\n\n## Project Structure\n\n```\nPgCrudApi/\n├── Controllers/\n│   ├── AuthController.cs         # Authentication \u0026 user management endpoints\n│   └── ProductsController.cs     # Product CRUD endpoints\n├── Data/\n│   ├── ProductDbContext.cs       # Database context\n│   └── Migrations/                # EF Core migrations\n│       ├── InitialCreate.cs      # Initial Products table\n│       └── AddUserTable.cs       # User authentication table\n├── Dtos/\n│   ├── AuthResponseDto.cs        # JWT token response\n│   ├── LoginDto.cs               # Login request\n│   ├── RegisterDto.cs            # User registration request\n│   ├── UserDto.cs                # User response\n│   ├── UpdateUserDto.cs          # Update user request\n│   ├── CreateProductDto.cs       # Create product request\n│   ├── ProductDto.cs             # Product response\n│   └── UpdateProductDto.cs       # Update product request\n├── mapper/\n│   ├── ProductMapping.cs         # Product entity-DTO mappings\n│   └── UserMapping.cs            # User entity-DTO mappings\n├── Models/\n│   ├── Product.cs                # Product entity\n│   └── User.cs                   # User entity\n├── Properties/\n│   └── launchSettings.json       # Launch configuration\n├── SwaggerAuthOperationFilter.cs # Swagger JWT authentication filter\n├── appsettings.json              # App configuration (connection strings, JWT)\n├── Program.cs                    # Application entry point \u0026 middleware setup\n└── PgCrudApi.csproj              # Project file \u0026 NuGet packages\n```\n\n## Database Schema\n\n### Users Table\n\n| Column | Type | Constraints | Description |\n|--------|------|-------------|-------------|\n| Id | int | PRIMARY KEY, AUTO_INCREMENT | Unique user identifier |\n| Username | string(100) | REQUIRED, UNIQUE | User's username |\n| Email | string(200) | REQUIRED, UNIQUE | User's email address |\n| PasswordHash | string | REQUIRED | Hashed password (SHA-256) |\n| CreatedAt | datetime | DEFAULT UTC NOW | Account creation timestamp |\n\n### Products Table\n\n| Column | Type | Constraints | Description |\n|--------|------|-------------|-------------|\n| Id | int | PRIMARY KEY, AUTO_INCREMENT | Unique product identifier |\n| Name | string | REQUIRED | Product name |\n| Description | string | REQUIRED | Product description |\n| Price | decimal | REQUIRED | Product price |\n| CreatedAt | datetime | DEFAULT UTC NOW | Creation timestamp |\n\n## Security Features\n\n- **JWT Authentication**: Secure token-based authentication\n- **Password Hashing**: SHA-256 hashing for password security\n- **Protected Endpoints**: All product and user management endpoints require authentication\n- **Token Expiration**: Tokens expire after 60 minutes (configurable)\n- **Duplicate Prevention**: Email and username uniqueness validation\n- **CORS Configuration**: Configured for cross-origin requests\n\n## Development\n\n### Adding New Migrations\n\nWhen you modify the entity models, create a new migration:\n\n```bash\n# Create a new migration\ndotnet ef migrations add YourMigrationName\n\n# Apply the migration to database\ndotnet ef database update\n```\n\n### Remove Last Migration\n\n```bash\ndotnet ef migrations remove\n```\n\n### View Migration SQL\n\n```bash\ndotnet ef migrations script\n```\n\n## Common Issues \u0026 Solutions\n\n### 1. Database Connection Errors\n**Issue:** Cannot connect to PostgreSQL database\n\n**Solution:**\n- Ensure PostgreSQL service is running\n- Verify connection string credentials in `appsettings.json`\n- Check PostgreSQL port (default: 5432)\n- Verify database exists or run migrations to create it\n\n### 2. JWT Authentication Errors\n**Issue:** 401 Unauthorized when calling protected endpoints\n\n**Solution:**\n- Ensure you have registered/logged in and received a JWT token\n- Include the token in the Authorization header: `Bearer YOUR_TOKEN`\n- Check token expiration (default: 60 minutes)\n- Verify JWT configuration in `appsettings.json`\n\n### 3. Migration Errors\n**Issue:** Migration failed or database out of sync\n\n**Solution:**\n- Ensure EF Core tools are installed: `dotnet tool install --global dotnet-ef`\n- Delete the database and run migrations again\n- Check for conflicting migrations\n- Verify connection string is correct\n\n### 4. CORS Errors\n**Issue:** CORS policy blocking requests\n\n**Solution:**\n- Verify CORS policy in `Program.cs`\n- Ensure your frontend URL is in the allowed origins\n- Check that CORS middleware is properly configured\n\n### 5. Swagger Not Loading\n**Issue:** Swagger UI not accessible\n\n**Solution:**\n- Ensure application is running in Development mode\n- Check `launchSettings.json` for environment settings\n- Navigate to correct URL: `http://localhost:5163/swagger/index.html`\n\n## Testing with Swagger\n\n1. **Start the application**: `dotnet run`\n2. **Open Swagger UI**: Navigate to `http://localhost:5163/swagger/index.html`\n3. **Register a user**:\n   - Expand `POST /api/auth/register`\n   - Click \"Try it out\"\n   - Fill in the request body\n   - Click \"Execute\"\n   - Copy the `token` from the response\n4. **Authorize**:\n   - Click the \"Authorize\" button (lock icon) at the top right\n   - Enter: `Bearer YOUR_TOKEN_HERE`\n   - Click \"Authorize\" then \"Close\"\n5. **Test protected endpoints**: Now you can test all product and user endpoints!\n\n## Environment Variables\n\nFor production, consider using environment variables instead of storing sensitive data in `appsettings.json`:\n\n```bash\n# Windows PowerShell\n$env:ConnectionStrings__DefaultConnection = \"Host=your-host;Port=5432;Database=pgcruddb;Username=user;Password=pass\"\n$env:Jwt__Key = \"YourProductionSecretKey\"\n\n# Linux/Mac\nexport ConnectionStrings__DefaultConnection=\"Host=your-host;Port=5432;Database=pgcruddb;Username=user;Password=pass\"\nexport Jwt__Key=\"YourProductionSecretKey\"\n```\n\n## API Response Codes\n\n| Status Code | Description |\n|-------------|-------------|\n| 200 OK | Request successful |\n| 201 Created | Resource created successfully |\n| 204 No Content | Request successful (no response body) |\n| 400 Bad Request | Invalid request data or validation error |\n| 401 Unauthorized | Missing or invalid JWT token |\n| 404 Not Found | Resource not found |\n| 500 Internal Server Error | Server error |\n\n## Contributing\n\nContributions are welcome! Please follow these steps:\n\n1. Fork the project\n2. Create your feature branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n## License\n\nThis project is open source and available for educational purposes.\n\n## Author\n\nhttps://rafiq15.github.io/\n\n## Acknowledgments\n\n- ASP.NET Core documentation\n- Entity Framework Core documentation\n- PostgreSQL community\n\n---\n\n**Note:** This is a demonstration project. For production use, consider implementing:\n- More secure password hashing (e.g., BCrypt, Argon2)\n- Refresh tokens for better security\n- Role-based authorization (Admin, User roles)\n- Input validation and sanitization\n- Rate limiting to prevent abuse\n- Logging and monitoring\n- Comprehensive error handling\n- Unit and integration tests\n- API versioning\n- Health check endpoints\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafiq15%2Faspnet-postgresql-crud-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frafiq15%2Faspnet-postgresql-crud-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafiq15%2Faspnet-postgresql-crud-api/lists"}