This is a Talabat Clone Project built in in Onion Architecture Based on the following Design Patterns:
- Repository Design Pattern.
- Specification Design Pattern.
- UnitOfWork Design Pattern.
- Builder Design Pattern.
- Work on Mac,Linux and Windows.
- Support other version Control Systems.
- Implements open for extension closed for modification Principle (OCP).
- Handling with all error types and validations(400-401-404-500).
- Using Lazy and Eager Loading Techniques.
- Adding Custom Middlewares for Authentication and Authoriziation.
- StackExchange.Redis.
- Microsoft.EntityFrameworkCore.Tools.
- Microsoft.EntityFrameworkCore.SqlServer.
- Microsoft.AspNetCore.Identity.EntityFrameworkCore.
- AutoMapper.Extensions.Microsoft.DependencyInjection.
- Microsoft.AspNetCore.Authentication.JwtBearer.
- Stripe.net.
- TalabatAPIs.
- TalabatIdentityAPIs.
- Redis (open source, in-memory database).
Just clone the project
Run on Visual Studio
Test endpoints on Postman
├── Talabat APIs | ├──Controllers | | ├──AccountController.cs | | ├──BaseAPIController.cs | | ├──BasketController.cs | | ├──ProductsController.cs | | ├──OrdersController.cs | | └──PaymentsController.cs | ├──Dtos | | ├──LoginDto.cs | | ├──ProductDto.cs | | ├──RegisterDto.cs | | ├──UserDto.cs | | ├──AddressDto.cs | | ├──BasketItemDto.cs | | ├──CustomerBasketDto.cs | | ├──OrderDto.cs | | ├──OrderToReturnDto.cs | | └──OrderItemDto.cs | ├──Errors | | ├──ApiExceptionError.cs | | ├──ApiResponse.cs | | └──ApiValidationErrorResponse.cs | ├──Extensions | | ├──AppServicesExtension.cs | | ├──IdentityServicesExtension.cs | | ├──SwaggerServicesExtension.cs | | └──UserManagerExtensions | ├──Helpers | | ├──MappingProfiles.cs | | ├──Pagination.cs | | ├──ProductPictureUrlResolver.cs | | └──CachedAttribute.cs | ├──Middlewares | | └──ExceptionMiddleware.cs | ├──appsettings.json | ├──Program.cs | └──Startup.cs ├── Talabat.Core | ├──Entities | | ├──Identity | | | ├──Address.cs | | | └──AppUser.cs | | ├──BaseEntity.cs | | ├──BasketItem.cs | | ├──CustomerBasket.cs | | ├──Product.cs | | ├──ProductBrand.cs | | ├──ProductType.cs | | ├──Order Aggregate | | | ├──Address.cs | | | ├──DeliveryMethod.cs | | | ├──Order.cs | | | ├──OrderItem.cs | | | ├──OrderStatus.cs | | | └──ProductItemOrdered.cs | ├──Repositories | | ├──IBasketRepository.cs | | ├──IGenericRepository.cs | | └──IUnitOfWork.cs | ├──Servicecs | | ├──ITokenService.cs | | ├──IOrderService.cs | | ├──IPaymentService.cs | | └──IResponseCacheService.cs | ├──Specification | | ├──BaseSpecification.cs | | ├──ISpecification.cs | | ├──ProductSpecificationFilterCount.cs | | ├──ProductsSpecParams.cs | | ├──ProductWithBrandAndTypeSpecification.cs | | ├──OrderWithItemsAndDeliveryMethodsSpecification.cs | | └──OrderByPaymentIntentIdSpecification ├── Talabat.Repository | ├──Data | | ├──Config | | | ├──ProductConfiguration.cs | | | ├──OrderConfiguration.cs | | | ├──OrderItemConfiguration.cs | | | └──DeliveryMethodConfiguration.cs | | ├──Migrations | | ├──SpecificationEvaluator.cs | | ├──StoreContext.cs | | ├──StoreContextSeed.cs | ├──DataSeed | | ├──brands.json | | ├──products.json | | ├──types.json | | └──delivery.json | ├──Identity | | ├──Migrations | | ├──AppIdentityContext.cs | | └──AppIdentityContextSeed.cs | ├──BasketRepository.cs | ├──GenericRepository.cs | ├──UnitOfWork.cs ├── Talabat.Service | ├──TokenService.cs | ├──OrderService.cs | ├──PaymentService.cs | └──ResponseCacheService.cs
-
Onion Architecture uses the concept of layers, but they are different from 3-tier and n-tier architecture layers. Let’s see what each of these layers represents and should contain.
-
Domain Layer
- At the center part of the Onion Architecture, the domain layer exists; this layer represents the business and behavior objects. The idea is to have all of your domain objects at this core. It holds all application domain objects. Besides the domain objects, you also could have domain interfaces. These domain entities don’t have any dependencies. Domain objects are also flat as they should be, without any heavy code or dependencies
-
Repository Layer
- This layer creates an abstraction between the domain entities and business logic of an application. In this layer, we typically add interfaces that provide object saving and retrieving behavior typically by involving a database. This layer consists of the data access pattern, which is a more loosely coupled approach to data access. We also create a generic repository, and add queries to retrieve data from the source, map the data from data source to a business entity, and persist changes in the business entity to the data source.
-
Service Layer
- The Service layer holds interfaces with common operations, such as Add, Save, Edit, and Delete. Also, this layer is used to communicate between the UI layer and repository layer. The Service layer also could hold business logic for an entity. In this layer, service interfaces are kept separate from its implementation, keeping loose coupling and separation of concerns in mind.
-
Presentation Layer
- It’s the outer-most layer, and keeps peripheral concerns like UI and tests. For a Web application, it represents the Web API or Unit Test project. This layer has an implementation of the dependency injection principle so that the application builds a loosely coupled structure and can communicate to the internal layer via interfaces.
GET /api/Products/Brands
GET /api/Products/Types
GET /api/Products?sort=${price}&TypeId=${TypeId}&BrandId=${BrandId}&PageSize=${PageSize}&PageIndex=${PageIndex}&search=${Name}
Parameter | Type | Status | Description |
---|---|---|---|
sort |
string |
Not Required | Sort the products by price or name descending or ascending order |
TypeId |
int |
Not Required | Id of Type to fetch. |
BrandId |
int |
Not Required | Id of Brand to fetch. |
PageSize |
int |
Not Required | To determine tge page size of products (Pagination). |
PageIndex |
int |
Not Required | To get specific page index. |
Name |
string |
Not Required | To search for all prducts that include this word in their Name. |
GET /api/Basket?Id=${id}
Parameter | Type | Status | Description |
---|---|---|---|
Id |
string |
Required | .Id of Basket to fetch. |
POST /api/Basket
{
"id": "basket1",
"items": [
{
"id": 4,
"Name": ".NET Black & White Mug",
"price": 10,
"quantity": 40,
"pictureUrl": "https://localhost:5001/images/products/2.png",
"brand": ".NET",
"type": "USB Memory Stick"
}
],
"deliveryMethodId": 1
}
DELETE /api/Basket?Id=${id}
Parameter | Type | Status | Description |
---|---|---|---|
Id |
string |
Required | Id of Basket to be deleted. |
POST /api/Account/login
{
"Email": "[email protected]",
"Password": "Yousef2*"
}
POST /api/Account/register
{
"DisplayName":"yousef",
"Email": "[email protected]",
"Password": "Yousef2*",
"PhoneNumber": "01552851677"
}
GET /api/Account/GetCurrentUser
GET /api/Account/Address
PUT /api/Account/UpdateCurrentUserAddress
{
"FirstName": "yousef new",
"LastName": "osama new",
"street": "42-EltalStreet new",
"city": "Warraq-Giza new",
"country": "Egypt new"
}
GET /api/Orders/DeliveryMethods
GET /api/Orders
GET /api/Orders/1
POST /api/Orders
{
"basketId": "basket1",
"deliveryMethodId": 1,
"shippingaddress": {
"FirstName": "yousef osama",
"LastName": "mohamed",
"street": "42-EltalStreet new",
"city": "Warraq-Giza new",
"country": "Egypt new"
}
}
- To Confirm Payment with the Gateway and handling stripe Events with success or fail.
POST /Payments/webhook
POST /api/Payments?basketId=${basketId}
Parameter | Type | Status | Description |
---|---|---|---|
Id |
string |
Required | Id of Basket to be Ordered. |
Many API endpoints return the JSON representation of the resources created or edited. However, if an invalid request is submitted, or some other error occurs, Talabat returns a JSON response in the following format:
{
"message" : string,
"statusCode" : int,
"Details" : string
}
The message
attribute contains a message commonly used to indicate errors.
The statusCode
attribute describes the code of the response due to the follwing Status Codes Table.
The Details
attribute contains error message only in developing env and in case of internal server error(500).
Talabat returns the following status codes in its API:
Status Code | Description |
---|---|
200 | OK |
400 | BAD REQUEST |
401 | UNAUTHORIZED |
404 | NOT FOUND |
500 | INTERNAL SERVER ERROR |
How To Pay Through Application ?
You should enter any future date and any valid three numbers for CVC
and the card number can be got by
Stripe PaymentGateway
.
What About Perfomance For High Traffic Requests ?
The caching is done for only 10 minutes for products loaded before.
How To Connect To Redis ?
- First Install Redis Software.
- Open the Command prompt and type this command
redis-server
.
Yousef |