Skip to content
Snippets Groups Projects
Commit ac41b420 authored by Abdelsamad, Mouaz R (UG - SISC)'s avatar Abdelsamad, Mouaz R (UG - SISC)
Browse files

Merge branch 'MA/Gateway' into 'main'

Gateway API Service

See merge request ma03081/COM3014!10
parents dac711d5 c7dbb436
No related branches found
No related tags found
No related merge requests found
Showing
with 563 additions and 5 deletions
# Image settings
IMAGE_TAG=0.0.1
MYSQL_IMAGE_TAG=8.0
# Database configuration
DB_PORT=3308
DB_NAME=AspNetCoreDb
DB_USER=root
DB_PASSWORD=
DB_PORT=3307
DB_NAME=myDB
DB_USER=user
DB_PASSWORD=user
DB_CHARSET=utf8mb4
# Service ports
USER_MICROSERVICE_PORT=5089 # This port will be used as the JWT issuer
USER_MICROSERVICE_PORT=5089
FLIGHT_MICROSERVICE_PORT=5175
GATEWAY_API_PORT=5267
CLIENT_PORT=4200
\ No newline at end of file
CREATE TABLE Users (
Id INT AUTO_INCREMENT PRIMARY KEY,
Username LONGTEXT NOT NULL,
Email LONGTEXT NOT NULL,
PasswordHash LONGTEXT NOT NULL,
Type INT NOT NULL
);
CREATE TABLE RefreshTokens (
Id INT AUTO_INCREMENT PRIMARY KEY,
UserId INT NOT NULL,
Token LONGTEXT NOT NULL,
ExpirationDate DATETIME(6) NOT NULL
);
CREATE TABLE Flights (
Id INT AUTO_INCREMENT PRIMARY KEY,
Origin LONGTEXT NOT NULL,
Destination LONGTEXT NOT NULL,
DepartureTime DATETIME(6) NOT NULL,
ArrivalTime DATETIME(6) NOT NULL,
EconomyCapacity INT NOT NULL,
BusinessCapacity INT NOT NULL,
EconomyPrice DECIMAL(65, 30) NOT NULL,
BusinessPrice DECIMAL(65, 30) NOT NULL
);
CREATE TABLE Seats (
Id INT AUTO_INCREMENT PRIMARY KEY,
FlightId INT NOT NULL,
SeatNumber LONGTEXT NOT NULL,
ClassType INT NOT NULL,
IsAvailable TINYINT(1) NOT NULL
);
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
\ No newline at end of file
using GatewayAPI.Models;
namespace GatewayAPI.Clients.FlightService
{
public class FlightServiceClient : IFlightServiceClient
{
private readonly HttpClient httpClient;
private static readonly string FLIGHT_API_PATH = "api/Flight";
private static readonly string SEAT_API_PATH = "api/Seat";
public FlightServiceClient(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task<HttpResponseMessage> GetFlightAsync(int flightId)
{
return await httpClient.GetAsync($"{FLIGHT_API_PATH}/{flightId}");
}
public async Task<HttpResponseMessage> GetFlightsAsync(string? origin = null, string? destination = null, DateTime? departureTime = null, DateTime? arrivalTime = null)
{
var queryParams = new List<string>();
if (origin != null)
queryParams.Add($"origin={Uri.EscapeDataString(origin)}");
if (destination != null)
queryParams.Add($"destination={Uri.EscapeDataString(destination)}");
if (departureTime.HasValue)
queryParams.Add($"departureTime={departureTime.Value.ToString("yyyy-MM-dd HH:mm:ss.fff") + "000"}");
if (arrivalTime.HasValue)
queryParams.Add($"arrivalTime={arrivalTime.Value.ToString("yyyy-MM-dd HH:mm:ss.fff") + "000"}");
string queryString = queryParams.Any() ? $"?{string.Join("&", queryParams)}" : string.Empty;
return await httpClient.GetAsync($"{FLIGHT_API_PATH}{queryString}");
}
public async Task<HttpResponseMessage> AddFlightAsync(FlightCreation flight)
{
return await httpClient.PostAsJsonAsync(FLIGHT_API_PATH, flight);
}
public async Task<HttpResponseMessage> GetFlightCapacityAsync(int flightId, int classType)
{
return await httpClient.GetAsync($"{FLIGHT_API_PATH}/{flightId}/capacity?ClassType={classType}");
}
public async Task<HttpResponseMessage> GetSeatsAsync()
{
return await httpClient.GetAsync(SEAT_API_PATH);
}
public async Task<HttpResponseMessage> GetSeatAsync(int seatId)
{
return await httpClient.GetAsync($"{SEAT_API_PATH}/{seatId}");
}
public async Task<HttpResponseMessage> IsSeatAvailableAsync(int seatId)
{
return await httpClient.GetAsync($"{SEAT_API_PATH}/{seatId}/isAvailable");
}
public async Task<HttpResponseMessage> BookSeatAsync(int seatId)
{
return await httpClient.PutAsync($"{SEAT_API_PATH}/{seatId}", null);
}
}
}
using GatewayAPI.Models;
namespace GatewayAPI.Clients.FlightService
{
public interface IFlightServiceClient
{
Task<HttpResponseMessage> GetFlightAsync(int flightId);
Task<HttpResponseMessage> GetFlightsAsync(string? origin = null, string? destination = null, DateTime? departureTime = null, DateTime? arrivalTime = null);
Task<HttpResponseMessage> AddFlightAsync(FlightCreation flight);
Task<HttpResponseMessage> GetFlightCapacityAsync(int flightId, int classType);
Task<HttpResponseMessage> GetSeatsAsync();
Task<HttpResponseMessage> GetSeatAsync(int seatId);
Task<HttpResponseMessage> IsSeatAvailableAsync(int seatId);
Task<HttpResponseMessage> BookSeatAsync(int seatId);
}
}
using GatewayAPI.Models;
namespace GatewayAPI.Clients.UserService
{
public interface IUserServiceClient
{
Task<HttpResponseMessage> GetUserAsync(int id);
Task<HttpResponseMessage> GetUsersAsync();
Task<HttpResponseMessage> RegisterUserAsync(UserRegistration user);
Task<HttpResponseMessage> LoginUserAsync(UserLogin user);
Task<HttpResponseMessage> AuthorizeUserAsync();
Task<HttpResponseMessage> LogoutUserAsync();
Task<HttpResponseMessage> UpdateUserAsync(int id, UserUpdateInfo updateInfo);
}
}
using GatewayAPI.Models;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
namespace GatewayAPI.Clients.UserService
{
public class UserServiceClient : IUserServiceClient
{
private readonly HttpClient httpClient;
private static readonly string API_PATH = "api/User";
public UserServiceClient(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task<HttpResponseMessage> GetUserAsync(int id)
{
return await httpClient.GetAsync($"{API_PATH}/{id}");
}
public async Task<HttpResponseMessage> GetUsersAsync()
{
return await httpClient.GetAsync($"{API_PATH}");
}
public async Task<HttpResponseMessage> RegisterUserAsync(UserRegistration user)
{
return await httpClient.PostAsJsonAsync($"{API_PATH}/register", user);
}
public async Task<HttpResponseMessage> LoginUserAsync(UserLogin user)
{
return await httpClient.PostAsJsonAsync($"{API_PATH}/login", user);
}
public async Task<HttpResponseMessage> AuthorizeUserAsync()
{
return await httpClient.PostAsync($"{API_PATH}/authorize", null);
}
public async Task<HttpResponseMessage> LogoutUserAsync()
{
return await httpClient.PostAsync($"{API_PATH}/logout", null);
}
public async Task<HttpResponseMessage> UpdateUserAsync(int id, UserUpdateInfo updateInfo)
{
return await httpClient.PatchAsJsonAsync($"{API_PATH}/{id}", updateInfo);
}
}
}
using GatewayAPI.Clients.FlightService;
using GatewayAPI.Clients.UserService;
using GatewayAPI.Models;
using Microsoft.AspNetCore.Mvc;
namespace GatewayAPI.Controllers
{
[ApiController]
[Route("api/[Controller]")]
public class FlightController : ControllerBase
{
private readonly IFlightServiceClient flightServiceClient;
public FlightController(IFlightServiceClient flightServiceClient)
{
this.flightServiceClient = flightServiceClient;
}
[HttpGet()]
public async Task<IActionResult> GetFlights(string? origin = null, string? destination = null, DateTime? departureTime = null, DateTime? arrivalTime = null)
{
HttpResponseMessage response = await flightServiceClient.GetFlightsAsync(origin, destination, departureTime, arrivalTime);
return new HttpResponseMessageResult(response);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetFlights(int id)
{
HttpResponseMessage response = await flightServiceClient.GetFlightAsync(id);
return new HttpResponseMessageResult(response);
}
[HttpPost()]
public async Task<IActionResult> AddFlight([FromBody] FlightCreation flightCreation)
{
HttpResponseMessage response = await flightServiceClient.AddFlightAsync(flightCreation);
return new HttpResponseMessageResult(response);
}
[HttpGet("{id}/capacity")]
public async Task<IActionResult> GetFlightCapacity([FromRoute] int id, [FromQuery] int classType)
{
HttpResponseMessage response = await flightServiceClient.GetFlightCapacityAsync(id, classType);
return new HttpResponseMessageResult(response);
}
}
}
using GatewayAPI.Clients.FlightService;
using Microsoft.AspNetCore.Mvc;
namespace GatewayAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class SeatController : ControllerBase
{
private readonly IFlightServiceClient flightServiceClient;
public SeatController(IFlightServiceClient flightServiceClient)
{
this.flightServiceClient = flightServiceClient;
}
[HttpGet()]
public async Task<IActionResult> GetSeats()
{
HttpResponseMessage response = await flightServiceClient.GetSeatsAsync();
return new HttpResponseMessageResult(response);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetSeats(int id)
{
HttpResponseMessage response = await flightServiceClient.GetSeatAsync(id);
return new HttpResponseMessageResult(response);
}
[HttpPut("{id}")]
public async Task<IActionResult> BookSeat(int id)
{
HttpResponseMessage response = await flightServiceClient.BookSeatAsync(id);
return new HttpResponseMessageResult(response);
}
[HttpGet("{id}/isAvailable")]
public async Task<IActionResult> IsAvailable(int id)
{
HttpResponseMessage response = await flightServiceClient.IsSeatAvailableAsync(id);
return new HttpResponseMessageResult(response);
}
}
}
using GatewayAPI.Clients.UserService;
using GatewayAPI.Models;
using Microsoft.AspNetCore.Mvc;
using System.Text;
namespace GatewayAPI.Controllers
{
[ApiController]
[Route("api/[Controller]")]
public class UserController : ControllerBase
{
private readonly IUserServiceClient userServiceClient;
public UserController(IUserServiceClient userServiceClient)
{
this.userServiceClient = userServiceClient;
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] UserRegistration userRegistration)
{
HttpResponseMessage response = await userServiceClient.RegisterUserAsync(userRegistration);
return new HttpResponseMessageResult(response);
}
[HttpPost("authorize")]
public async Task<IActionResult> Authorize()
{
HttpResponseMessage response = await userServiceClient.AuthorizeUserAsync();
return new HttpResponseMessageResult(response);
}
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] UserLogin userLogin)
{
HttpResponseMessage response = await userServiceClient.LoginUserAsync(userLogin);
return new HttpResponseMessageResult(response);
}
[HttpPost("logout")]
public async Task<IActionResult> Logout()
{
HttpResponseMessage response = await userServiceClient.LogoutUserAsync();
return new HttpResponseMessageResult(response);
}
[HttpGet()]
public async Task<IActionResult> GetUsers()
{
HttpResponseMessage response = await userServiceClient.GetUsersAsync();
return new HttpResponseMessageResult(response);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
HttpResponseMessage response = await userServiceClient.GetUserAsync(id);
return new HttpResponseMessageResult(response);
}
[HttpPatch("{id}")]
public async Task<IActionResult> UpdateUser(int id, [FromBody] UserUpdateInfo updateInfo)
{
HttpResponseMessage response = await userServiceClient.UpdateUserAsync(id, updateInfo);
return new HttpResponseMessageResult(response);
}
}
}
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["GatewayAPI.csproj", "."]
RUN dotnet restore "./GatewayAPI.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./GatewayAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./GatewayAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "GatewayAPI.dll"]
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>50dbee94-e07d-4906-85d3-8337755e0027</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>http</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
\ No newline at end of file
@GatewayAPI_HostAddress = http://localhost:5267
GET {{GatewayAPI_HostAddress}}/weatherforecast/
Accept: application/json
###

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatewayAPI", "GatewayAPI.csproj", "{2ABFA760-35A9-4BF8-ADAF-3751CCC8C20A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2ABFA760-35A9-4BF8-ADAF-3751CCC8C20A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2ABFA760-35A9-4BF8-ADAF-3751CCC8C20A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2ABFA760-35A9-4BF8-ADAF-3751CCC8C20A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2ABFA760-35A9-4BF8-ADAF-3751CCC8C20A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7FFD5B8C-F828-4EBE-B2B7-888D63CDE589}
EndGlobalSection
EndGlobal
using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using System.Threading.Tasks;
namespace GatewayAPI
{
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
this.responseMessage = responseMessage ?? throw new ArgumentNullException(nameof(responseMessage));
}
public async Task ExecuteResultAsync(ActionContext context)
{
HttpContext httpContext = context.HttpContext;
HttpResponse response = httpContext.Response;
response.ContentType = "application/json; charset=utf-8";
// Copy the status code
response.StatusCode = (int)responseMessage.StatusCode;
// Copy the cookies
if (responseMessage.Headers.TryGetValues("Set-Cookie", out var cookieValues))
{
foreach (string cookie in cookieValues)
response.Headers.Append("Set-Cookie", cookie);
}
// Copy the response body directly to the response stream
using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(response.Body);
await response.Body.FlushAsync();
}
}
}
}
namespace GatewayAPI.Models
{
public class FlightCreation
{
public required string Origin { get; set; }
public required string Destination { get; set; }
public required DateTime DepartureTime { get; set; }
public required DateTime ArrivalTime { get; set; }
public required int EconomyCapacity { get; set; }
public required int BusinessCapacity { get; set; }
public required decimal EconomyPrice { get; set; }
public required decimal BusinessPrice { get; set; }
}
}
namespace GatewayAPI.Models
{
public class UserLogin
{
public required string Username { get; set; }
public required string Password { get; set; }
}
}
namespace GatewayAPI.Models
{
public class UserRegistration
{
public required string Username { get; set; }
public required string Email { get; set; }
public required string Password { get; set; }
public required int UserType { get; set; }
}
}
namespace GatewayAPI.Models
{
public class UserUpdateInfo
{
public string? Username { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment