BFF Purchase - WIP

This commit is contained in:
Eduard Tomàs 2018-01-29 15:58:08 +00:00
parent 02f5e1158a
commit 47a33ddd05
20 changed files with 271 additions and 17 deletions

View File

@ -29,4 +29,5 @@ cli-linux
**/node_modules/ **/node_modules/
**/bower_components/ **/bower_components/
**/wwwroot/lib/ **/wwwroot/lib/
global.json global.json
**/appsettings.localhost.json

View File

@ -231,6 +231,8 @@ services:
purchasebff: purchasebff:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- urls__basket=http://basket.api
- urls__catalog=http://catalog.api
ports: ports:
- "5120:80" - "5120:80"

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Config
{
public class UrlsConfig
{
public class CatalogOperations
{
public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}";
}
public class BasketOperations
{
public static string GetItemById(string id) => $"/api/v1/basket/{id}";
}
public string Basket { get; set; }
public string Catalog { get; set; }
}
}

View File

@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using PurchaseBff.Models;
using PurchaseBff.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -9,12 +11,38 @@ namespace PurchaseBff.Controllers
[Route("api/v1/[controller]")] [Route("api/v1/[controller]")]
public class BasketController : Controller public class BasketController : Controller
{ {
[HttpPost("items/{catalogItemId}")] private readonly ICatalogService _catalog;
public async Task<IActionResult> AddBasketItem(int catalogItemId) private readonly IBasketService _basket;
public BasketController(ICatalogService catalogService, IBasketService basketService)
{ {
_catalog = catalogService;
_basket = basketService;
}
[HttpPost("items")]
public async Task<IActionResult> AddBasketItem([FromBody] AddBasketItemRequest data)
{
if (data == null || data.Quantity == 0)
{
return BadRequest("Invalid payload");
}
// Step 1: Get the item from catalog // Step 1: Get the item from catalog
var item = await _catalog.GetCatalogItem(data.CatalogItemId);
// Step 2: Get current basket status // Step 2: Get current basket status
var currentBasket = await _basket.GetById(data.BasketId);
// Step 3: Merge current status with new product // Step 3: Merge current status with new product
currentBasket.Items.Add(new BasketDataItem()
{
OldUnitPrice = item.Price,
UnitPrice = item.Price,
PictureUrl = item.PictureUri,
ProductId = item.Id.ToString(),
ProductName = item.Name,
Quantity = data.Quantity,
Id = item.Id.ToString()
});
// Step 4: Update basket // Step 4: Update basket
return Ok(); return Ok();

View File

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Controllers
{
[Route("")]
public class HomeController : Controller
{
[HttpGet()]
public IActionResult Index()
{
return new RedirectResult("~/swagger");
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Models
{
public class AddBasketItemRequest
{
public int CatalogItemId { get; set; }
public string BasketId { get; set; }
public int Quantity { get; set; }
public AddBasketItemRequest()
{
Quantity = 1;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Models
{
public class BasketData
{
public string BuyerId { get; set; }
public List<BasketDataItem> Items { get; set; }
public BasketData(string buyerId)
{
BuyerId = buyerId;
Items = new List<BasketDataItem>();
}
}
public class BasketDataItem
{
public string Id { get; set; }
public string ProductId { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public decimal OldUnitPrice { get; set; }
public int Quantity { get; set; }
public string PictureUrl { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Models
{
public class CatalogItem
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string PictureUri { get; set; }
}
}

View File

@ -20,6 +20,10 @@ namespace PurchaseBff
public static IWebHost BuildWebHost(string[] args) => public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args) WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>() .UseStartup<Startup>()
.ConfigureAppConfiguration(cb =>
{
cb.AddJsonFile("appsettings.localhost.json", optional: true);
})
.Build(); .Build();
} }
} }

View File

@ -20,4 +20,8 @@
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using PurchaseBff.Config;
using PurchaseBff.Models;
namespace PurchaseBff.Services
{
public class BasketService : IBasketService
{
private readonly IHttpClient _apiClient;
private readonly ILogger<BasketService> _logger;
private readonly UrlsConfig _urls;
public BasketService(IHttpClient httpClient, ILogger<BasketService> logger, IOptionsSnapshot<UrlsConfig> config)
{
_apiClient = httpClient;
_logger = logger;
_urls = config.Value;
}
public async Task<BasketData> GetById(string id)
{
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
var basket = JsonConvert.DeserializeObject<BasketData>(data);
return basket;
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using PurchaseBff.Config;
using PurchaseBff.Models;
namespace PurchaseBff.Services
{
public class CatalogService : ICatalogService
{
private readonly IHttpClient _apiClient;
private readonly ILogger<CatalogService> _logger;
private readonly UrlsConfig _urls;
public CatalogService(IHttpClient httpClient, ILogger<CatalogService> logger, IOptionsSnapshot<UrlsConfig> config)
{
_apiClient = httpClient;
_logger = logger;
_urls = config.Value;
}
public async Task<CatalogItem> GetCatalogItem(int id)
{
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var item = JsonConvert.DeserializeObject<CatalogItem>(data);
return item;
}
}
}

View File

@ -0,0 +1,13 @@
using PurchaseBff.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Services
{
public interface IBasketService
{
Task<BasketData> GetById(string id);
}
}

View File

@ -0,0 +1,13 @@
using PurchaseBff.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PurchaseBff.Services
{
public interface ICatalogService
{
Task<CatalogItem> GetCatalogItem(int id);
}
}

View File

@ -5,11 +5,14 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using PurchaseBff.Config;
using PurchaseBff.Filters.Basket.API.Infrastructure.Filters; using PurchaseBff.Filters.Basket.API.Infrastructure.Filters;
using PurchaseBff.Services;
using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.Swagger;
namespace PurchaseBff namespace PurchaseBff
@ -26,6 +29,14 @@ namespace PurchaseBff
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IHttpClient, StandardHttpClient>();
services.AddTransient<ICatalogService, CatalogService>();
services.AddTransient<IBasketService, BasketService>();
services.AddOptions();
services.Configure<UrlsConfig>(Configuration.GetSection("urls"));
services.AddMvc(); services.AddMvc();
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>

View File

@ -1,10 +0,0 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,6 @@
{
"urls": {
"basket": "http://localhost:55105",
"catalog": "http://localhost:55101"
}
}

View File

@ -3,7 +3,7 @@
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:63335/", "applicationUrl": "http://localhost:55105/",
"sslPort": 0 "sslPort": 0
} }
}, },
@ -19,7 +19,7 @@
"Microsoft.eShopOnContainers.Services.Basket.API": { "Microsoft.eShopOnContainers.Services.Basket.API": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "http://localhost:5000/swagger", "launchUrl": "http://localhost:55105/",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }

View File

@ -3,7 +3,7 @@
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:5101", "applicationUrl": "http://localhost:55101",
"sslPort": 0 "sslPort": 0
} }
}, },
@ -19,6 +19,7 @@
"Microsoft.eShopOnContainers.Services.Catalog.API": { "Microsoft.eShopOnContainers.Services.Catalog.API": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "http://localhost:55101/",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }

View File

@ -3,7 +3,7 @@
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:5110", "applicationUrl": "http://localhost:63455/",
"sslPort": 0 "sslPort": 0
} }
}, },