Skip to content

Jaser1010/E-Commerce.Web

Repository files navigation

E-Commerce Web API

Enterprise-Grade E-Commerce Backend Β· ASP.NET Core Β· Clean Onion Architecture

A production-ready, modular RESTful API for e-commerce β€” featuring JWT-based authentication, the Specification & Repository patterns, Redis-powered caching & shopping baskets, full order lifecycle management, Stripe payment integration, delivery method management, global exception handling with RFC 7807 ProblemDetails, and a strict onion architecture that isolates business logic from all infrastructure concerns.

πŸ“– Docs Β· πŸš€ Quick Start Β· πŸ› Report Bug Β· πŸ’‘ Request Feature


πŸ“‘ Table of Contents


⚑ Highlights

Feature Description
πŸ›οΈ Clean Onion Architecture 8 dedicated projects with strict inward-only dependency flow
πŸ” JWT Authentication Full user registration, login, email check & current-user retrieval, powered by ASP.NET Core Identity + JWT Bearer tokens
πŸ›’ Basket Module (Redis) Shopping cart persisted in Redis with create, update & delete support
πŸ“¦ Orders Module Full order lifecycle β€” create, retrieve all orders & retrieve a single order by ID, all tied to the authenticated user
🚚 Delivery Methods Configurable shipping options served from /api/orders/DeliveryMethods (no auth required)
πŸ’³ Stripe Payment Payment intent creation & confirmation via Stripe API
⚑ Redis Response Caching Custom [RedisCache] action filter attribute for automatic response caching
πŸ›‘οΈ Global Exception Handling Custom middleware returning RFC 7807 ProblemDetails responses
πŸ” Specification Pattern Composable, reusable query objects for filters, sorting, pagination & eager loading
πŸ“¦ Unit of Work + Generic Repository Transactional consistency with a single, type-safe abstraction
πŸ—ΊοΈ AutoMapper + Custom Resolvers Entity-to-DTO mapping with ProductPictureUrlResolver for dynamic image URLs
πŸ“Š Pagination, Sorting & Filtering Server-side pagination via PaginatedResult<T>, dynamic sorting & flexible query params
🏷️ Brands & Types Dedicated sub-endpoints to retrieve all product brands and product types

πŸ› Architecture Overview

This project follows Onion Architecture (also known as Clean Architecture), enforcing strict inward-only dependencies:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Presentation Layer                    β”‚
β”‚   (Controllers, Attributes, Action Filters)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Services Layer                       β”‚
β”‚  (AuthenticationService, OrderService,             β”‚
β”‚   BasketService, CacheService, ProductService)     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚          Services Abstraction Layer                β”‚
β”‚      (Interfaces, DTOs, Service Contracts)         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚             Persistence Layer                      β”‚
β”‚   (EF Core DbContext, Migrations, Repositories,    β”‚
β”‚    Unit of Work, Data Seeding)                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Shared Layer                         β”‚
β”‚     (Common Utilities, Constants, CommonResult)    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Domain Layer                         β”‚
β”‚      (Entities, Contracts, No dependencies)        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β–² Dependencies flow inward only β–²

πŸ“ Solution Structure

E-Commerce.Web.slnx
β”‚
β”œβ”€β”€ E Commerce.Domain/
β”‚   β”œβ”€β”€ Entities/
β”‚   β”‚   β”œβ”€β”€ ProductModule/              # Product, Brand, ProductType
β”‚   β”‚   β”œβ”€β”€ BasketModule/               # CustomerBasket, BasketItem
β”‚   β”‚   β”œβ”€β”€ OrderModule/                # Order, OrderItem, OrderAddress,
β”‚   β”‚   β”‚                               # DeliveryMethod, OrderStatus,
β”‚   β”‚   β”‚                               # ProductItemOrdered
β”‚   β”‚   └── IdentityModule/             # ApplicationUser
β”‚   └── Contracts/                      # Repository & Unit of Work interfaces
β”‚
β”œβ”€β”€ E Commerce.Persistence/
β”‚   β”œβ”€β”€ Data/                           # EF Core DbContext, migrations, seed data
β”‚   └── Repositories/                   # Generic & specific repository implementations
β”‚
β”œβ”€β”€ E Commerce.Services Abstraction/
β”‚   β”œβ”€β”€ IProductService.cs
β”‚   β”œβ”€β”€ IBasketService.cs
β”‚   β”œβ”€β”€ IOrderService.cs
β”‚   β”œβ”€β”€ IAuthenticationService.cs       # ✨ NEW β€” login, register, email check, current user
β”‚   └── DTOs/                           # Request / Response data transfer objects
β”‚       β”œβ”€β”€ ProductDTOs/
β”‚       β”œβ”€β”€ BasketDTOs/
β”‚       β”œβ”€β”€ OrderDTOs/
β”‚       └── IdentityDTOs/               # ✨ NEW β€” LoginDTO, RegisterDTO, UserDTO
β”‚
β”œβ”€β”€ E Commerce.Services/
β”‚   β”œβ”€β”€ ProductService.cs
β”‚   β”œβ”€β”€ BasketService.cs
β”‚   β”œβ”€β”€ OrderService.cs                 # ✨ NEW β€” full order creation & retrieval by ID
β”‚   β”œβ”€β”€ AuthenticationService.cs        # ✨ NEW β€” register, login, JWT generation (HMAC-SHA256)
β”‚   β”œβ”€β”€ CacheService.cs                 # ✨ NEW β€” Redis response cache abstraction
β”‚   β”œβ”€β”€ Specifications/                 # Composable query specification objects
β”‚   β”œβ”€β”€ MappingProfiles/                # AutoMapper profiles
β”‚   └── Exceptions/                     # Custom domain exception types
β”‚
β”œβ”€β”€ E Commerce.Presentation/
β”‚   β”œβ”€β”€ Controllers/
β”‚   β”‚   β”œβ”€β”€ ApiBaseController.cs
β”‚   β”‚   β”œβ”€β”€ ProductsController.cs       # ✨ UPDATED β€” now requires JWT; adds /brands & /types
β”‚   β”‚   β”œβ”€β”€ BasketsController.cs        # ✨ UPDATED β€” added DELETE endpoint
β”‚   β”‚   β”œβ”€β”€ OrdersController.cs         # ✨ NEW β€” create, get all, get by ID & delivery methods
β”‚   β”‚   └── AuthenticationController.cs # ✨ NEW β€” register, login, emailExists, currentUser
β”‚   └── Attributes/
β”‚       └── RedisCacheAttribute.cs      # ✨ NEW β€” declarative response caching
β”‚
β”œβ”€β”€ E Commerce.Shared/
β”‚   β”œβ”€β”€ CommonResult/                   # Result<T>, Error (NotFound, Validation, InvalidCredentials)
β”‚   └── (Shared utilities & constants)
β”‚
└── E-Commerce.Web/
    β”œβ”€β”€ CustomMiddleWares/              # ✨ NEW β€” global exception handling middleware
    β”œβ”€β”€ Extensions/                     # Service & middleware registration extensions
    β”œβ”€β”€ Factories/                      # Problem details factory
    β”œβ”€β”€ Program.cs
    β”œβ”€β”€ appsettings.json
    └── wwwroot/                        # Static assets (product images)

πŸ› οΈ Tech Stack

Category Technology
Framework ASP.NET Core 9 Web API
Language C# 13
ORM Entity Framework Core 9
Database SQL Server
Cache / Basket Store Redis (StackExchange.Redis)
Authentication ASP.NET Core Identity + JWT Bearer (HMAC-SHA256)
Object Mapping AutoMapper
API Documentation Swagger / OpenAPI (Swashbuckle)
Architecture Clean Onion Architecture

πŸ“– API Reference

πŸ” Authentication β€” /api/authentication

Method Endpoint Auth Description
POST /api/authentication/register ❌ Register a new user; returns UserDTO with JWT
POST /api/authentication/login ❌ Login and receive a JWT token
GET /api/authentication/emailExists?email= ❌ Check whether an email address is already registered
GET /api/authentication/CurrentUser βœ… JWT Get the current authenticated user's profile

UserDTO response:

{
  "email": "user@example.com",
  "displayName": "John Doe",
  "token": "<jwt-token>"
}

πŸ›οΈ Products β€” /api/products

Method Endpoint Auth Description
GET /api/products βœ… JWT Get all products (paginated, sortable, filterable) β€” cached via Redis
GET /api/products/{id} ❌ Get a single product by ID
GET /api/products/brands ❌ Get all available product brands
GET /api/products/types ❌ Get all available product types

Query Parameters for GET /api/products:

Parameter Type Description
pageIndex int Page number (default: 1)
pageSize int Items per page (default: 6)
sort string Sort field (e.g. priceAsc, priceDesc, nameAsc)
brandId int? Filter by brand ID
typeId int? Filter by type ID
search string? Search by product name

πŸ›’ Baskets β€” /api/baskets

Method Endpoint Auth Description
GET /api/baskets?id= ❌ Get a basket by its Redis key
POST /api/baskets ❌ Create or update a basket
DELETE /api/baskets/{id} ❌ Delete a basket by ID

πŸ“¦ Orders β€” /api/orders

Method Endpoint Auth Description
POST /api/orders βœ… JWT Create a new order from the authenticated user's basket
GET /api/orders βœ… JWT Get all orders for the authenticated user
GET /api/orders/{id} βœ… JWT Get a specific order by its GUID
GET /api/orders/DeliveryMethods ❌ Get all available delivery methods

OrderDTO request body:

{
  "basketId": "basket-123",
  "deliveryMethodId": 1,
  "shippingAddress": {
    "firstName": "John",
    "lastName": "Doe",
    "street": "123 Main St",
    "city": "Cairo",
    "country": "Egypt"
  }
}

πŸ’³ Payments β€” /api/payments

Method Endpoint Auth Description
POST /api/payments/{basketId} βœ… JWT Create or update a Stripe payment intent for a basket

πŸš€ Quick Start

Prerequisites

Step-by-Step Setup

1. Clone the repository

git clone https://github.com/Jaser1010/E-Commerce.Web.git
cd E-Commerce.Web

2. Start Redis (using Docker)

docker run -d --name redis-ecommerce -p 6379:6379 redis:alpine

3. Configure the application (appsettings.Development.json)

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=ECommerceDB;Trusted_Connection=True;",
    "RedisConnection": "localhost:6379"
  },
  "JWTOptions": {
    "SecretKey": "<your-secret-key-32-chars-min>",
    "Issuer": "ECommerceApp",
    "Audience": "ECommerceUsers"
  },
  "StripeSettings": {
    "SecretKey": "<your-stripe-secret-key>"
  }
}

4. Apply database migrations

dotnet ef database update --project "E Commerce.Persistence" --startup-project "E-Commerce.Web"

5. Run the application

dotnet run --project "E-Commerce.Web"

Swagger UI is available at: https://localhost:<port>/swagger


βš™οΈ Configuration

Key Description
ConnectionStrings:DefaultConnection SQL Server connection string
ConnectionStrings:RedisConnection Redis server address (e.g. localhost:6379)
JWTOptions:SecretKey Secret key for signing JWT tokens (min 32 characters)
JWTOptions:Issuer JWT token issuer
JWTOptions:Audience JWT token audience
StripeSettings:SecretKey Stripe secret API key

πŸ”¬ Design Patterns in Depth

Specification Pattern

Query objects (e.g. ProductWithBrandAndTypeSpecification) encapsulate filtering, sorting, pagination and eager loading:

// Composable, reusable, testable
var spec = new ProductWithBrandAndTypeSpecification(queryParams);
var products = await _unitOfWork.Repository<Product>().GetAllWithSpecAsync(spec);

Unit of Work + Generic Repository

A single IUnitOfWork gives type-safe access to all repositories and coordinates transactions:

var order = await _unitOfWork.Repository<Order>().GetByIdAsync(id);
await _unitOfWork.CompleteAsync();

Result Pattern (CommonResult)

All service methods return Result<T> β€” eliminating exceptions for expected failure scenarios:

// In AuthenticationService:
if (user is null)
    return Error.NotFound("User.NotFound", $"No user with email {email} was found");

return new UserDTO(user.Email!, user.DisplayName, token);

Redis Cache Attribute

Decorate any action with [RedisCache] to automatically cache the response:

[Authorize]
[HttpGet]
[RedisCache]
public async Task<ActionResult<PaginatedResult<ProductDTO>>> GetAllProducts(...)

πŸ›‘οΈ Error Handling

All errors are returned as RFC 7807 ProblemDetails via the global exception-handling middleware:

{
  "statusCode": 404,
  "message": "No User With Email user@example.com Was Found"
}

Authentication & validation errors use the Result<T> pattern with typed Error codes:

Error Type HTTP Status Example
NotFound 404 User or resource not found
InvalidCredentials 401 Wrong email or password
Validation 400 Identity validation errors on register

πŸ—ΊοΈ Roadmap

  • Clean Onion Architecture
  • Products & Baskets
  • Redis Caching
  • Global Exception Handling
  • JWT Authentication (register, login, email check, current user)
  • Product Brands & Types endpoints
  • Full Orders Module (create, get all, get by ID)
  • Delivery Methods
  • Basket Delete endpoint
  • Result Pattern (CommonResult)
  • Stripe Payment Integration
  • User address management
  • Real-time order status (SignalR)
  • Admin product management (CRUD)

🀝 Contributing

Contributions are welcome! Please open an issue first to discuss what you'd like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License.


πŸ‘€ Author

Jaser Kasim GitHub

About

ASP.NET Core Web API for an e-commerce application built with clean onion architecture. Implements RESTful endpoints for products, baskets, orders, and more.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages