π©βπ This is a WIP version!
0. Deployment
For the sake of simplicity, everything exists inside Docker Compose. Run to build and start the system:
docker-compose up --build
All methods are available through this API gateway.
Public IP addresses
API Gateway
http://localhost:4000
Consul
http://localhost:48500
Redis
http://localhost:46379
I. System Architecture
Service | Description |
---|---|
Identity | Issues JWT tokens. Stores users in an MongoDB database. |
Carsharing | Provides methods for searching, booking and returning cars. Stores cars in a MongoDB database. Requires JWT authentication. Does not provide methods for creating or removing cars from the database, i.e., cars simply exist. Does not have any payment mechanism, i.e., cars are free. |
Geocoding | Provides methods for converting an address to coordinates and vice versa. |
1. Identity Service
Method | Description |
---|---|
POST api/v1/identity/create Query parameters: username : string , required, unique password : string , required |
Creates a user with the specified username and password. |
GET api/v1/identity/jwt Query parameters: username : string , required password : string , required |
Issues a JWT for the specified user. |
2. Carsharing
Method | Description |
---|---|
GET api/v1/cars/available Query parameters: latitude : double , required longitude : double , required radius : double (meters), 500 meters by default |
Searches for available cars in the specified area. Only offers mock functionality, i.e., ignores coordinates and returns all available cars. |
POST api/v1/cars/book { CarId: string } |
Books a car with the specified Id . Accepts JSON. Not thread-safe. |
POST api/v1/cars/return { CarId: string, Latitude: double, Longitude: double } |
Marks a car with the specified Id as available and updates its location. Accepts JSON. |
Requires JWT authentication:
Authorization: Bearer <token>
Tokens are issued by api/v1/identity/jwt
.
3. Geocoding
Method | Description |
---|---|
GET api/v1/geocode/forward Query parameters: address : string , required |
Returns coordinates of the specified location. Only works for Uusimaa. |
GET api/v1/geocode/reverse Query parameters: latitude : double , required longitude : double , required |
Returns an address of the specified location. |
Source: HERE Geocoder API.
4. API Gateway
API gateway exposes with their original routes, e.g., api/v1/cars/available
is mapped to api/v1/cars/available
.
II. Aspects
1. Service Discovery
(1) Services register themselves in Consul on startup:
var ip = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork);
var port = 80;
...
consulClient.Agent.ServiceRegister(serviceRegistration).Wait();
(2) Services also register their api/v1/health
methods so that Consul can run health checks.
(3) API Gateway is implemented with Ocelot that offers a support for Consul service discovery:
"ServiceDiscoveryProvider": {
"Type": "Consul",
"Host": "consul",
"Port": 8500
}
Consul is only used to discover service IPs. MongoDB, Redis and Consul itself are accessed through their container names.
2. Dynamic Configuration
consul-template
daemon is used for dynamic configuration. At this point, only Carsharing
mircoservice includes support for dynamic configuration.
In order to change a configuration, a file with Carsharing/appsettings.json
key must be created in http://localhost:48500/ui/dc1/kv
. This will replace original service configuration file.
consul-template
is started in a Dockerfile and runs alongside with Carsharing.dll
:
./consul-template -consul-addr "consul:8500" -template "appsettings.tpl:appsettings.json"
dotnet Carsharing.dll
3. Caching
Geocoding
mircoservice caches the data retrieved from HERE Geocoder API in a Redis distributed cache:
services.AddDistributedRedisCache(options =>
{
options.Configuration = "redis:6379";
});
4. Authentication
Identity
mircoservice stores users in a MongoDB:
public class User
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("Username")]
public string Username { get; set; }
[BsonElement("Salt")]
public string Salt { get; set; }
[BsonElement("Hash")]
public string Hash { get; set; }
}
It validates username
+password
combinations and issues JWT tokens. Identity
and Carsharing
mircoservices share the symmetric security key.
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{
...
x.TokenValidationParameters = new TokenValidationParameters
{
...
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("secret")),
};
});
References
- Microsoft β Designing a microservice-oriented application
- Microsoft β Implement the microservice application layer using the Web API
- .NET Application Architecture: Reference Apps β eShopOnContainers
- Microsoft β Data considerations for microservices
- Microsoft β The API gateway pattern versus the Direct client-to-microservice communication
- Pitstop β Garage Management System
- Building Microservices with ASP.NET Core by Kevin Hoffman β Chapter 8. Service Discovery*
- GoogleCloudPlatform β Hipster Shop: Cloud-Native Microservices Demo Application
- Make secure .NET Microservices and Web Applications