REST API solution demonstrates how to create clean and modern API (from my point of view) with Clean Architecture, minimal API and various of design patterns.
Example API allows to get actual/forecast weather data by location from Weatherbit throught RapidAPI and also allow's to add favorite locations into in memory database and then get weather data by stored (favorites) locations.
- Register on RapidAPI
- Subscribe Weatherbit (its for free) and go to Endpoints tab
- In API documentation copy (from Code Snippet) X-RapidAPI-Key, X-RapidAPI-Host and put them to appsettings.json file in WeatherAPI project
"Weatherbit": {
"BaseUrl": "https://weatherbit-v1-mashape.p.rapidapi.com",
"XRapidAPIKey": "value from code snippet",
"XRapidAPIHost": "value from code snippet"
}
- Run Weather.API
- Go to Tests/Debug folder and open debug-tests.http file (in VS2022)
- Send request
Main motivation is to write practical example of minimal API, to see it's benefits and disadvantages. Also to create REST API example project using Clean Architecture and design patterns.
Projects folows Clean Architecture, but application layer is splitted to Core and Domain projects where Core project holds business rules and Domain project contains business entities.
As Minimal API allows to inject handlers into endpoint map methods, I decided to do not use MediatR, but still every endpoint has its own request and handler. Solution folows CQRS pattern, it means that handlers are separated by commands and queries, command handlers handle command requests and query handlers handle query requests. Also repositories (Repository pattern) are separated by command and queries.
Instead of throwing exceptions, project use Result pattern (using FluentResuls package) and for returning exact http response, every handler returns data wraped into HttpDataResponse object which contains also error messages collection and http response code.
Response value of every http status code is boxed into DataResponse class which holds result data and collection of errors. This approach allows for example return some error messages together with OK status code.
Important part of every project are tests. When writing tests we want to achieve optimal code coverage. I think that every project has its own optimal code coverage number by it's need and I always follow the rule: cover your code to be able refactor without worry about functionality change.
In this solution, each 'code' project has its own unit test project and every unit test project copy the same directory structure as 'code' project, which is very helpful for orientation in test project.
To ensure that our REST API works as expected for end users we write System tests. Typically we call endpoints of the API in particular order defined by business requirements and check expected results. The solution contains simple System Tests which just call exposed endpoints and check desired response.
- Reduce the ceremony of creating APIs
- no controllers (but you are still able to organize map methods in files)
- injects bussines handlers directly into endpoints map methods
- Minimal Hosting Model
- you are able to create single clean start point of the API
- UI/Framework/Database Independent
- business logic is in the middle so framework, database (any external layer) can be easily changed without major impacts
- Highly Testable
- clean architechture is designed for testing, for example business logic can be tested without touching any external layer/element like database, UI, external web service etc.
- easy to mock because of abstractions
- Maintain and Extensibility
- thanks to defined structure, changes has isolated impact and together with SOLID principles it's easy to maintain
- Understanding
- sometimes it's hard to split responsibilities or select right layer for our new code
- Heavy Structure
- it can be overkill to use it for simple CRUD api beacuse of lot of boilerplate code
Solution contains four layers:
- WeatherAPI - entry point of the application, top layer
- Endpoints
- Middlewares (or Filters)
- API Configuration
- Weather.Infrastructure - layer for communication with external resources like database, cache, web service..
- Repositories Implementation - access to database
- External Services Proxies - proxy classes implementation - to obtain data from external web services
- Infastructure Specific Services - services which are needed to interact with external libraries and frameworks
- Weatherbit.Client - standalone project for communication with RapidAPI/Weatherbit
- Weather.Core - business logic of the application
- Request Handlers/Managers/.. - business implementation
- Abstractions - besides abstractions for business logic are there abstractions for Infrastructure layer (Service, Repository, ..) to be able use them in this (core) layer
- Weather.Domain - all what should be shared across all projects
- DTOs
- General Extensions