{"id":141,"date":"2020-09-30T14:46:07","date_gmt":"2020-09-30T12:46:07","guid":{"rendered":"https:\/\/mtymejczyk.wordpress.com\/?p=141"},"modified":"2020-09-30T14:46:07","modified_gmt":"2020-09-30T12:46:07","slug":"coffeshop-cz-3-kontrolery-i-cqrs","status":"publish","type":"post","link":"https:\/\/tymejczyk.net\/index.php\/2020\/09\/30\/coffeshop-cz-3-kontrolery-i-cqrs\/","title":{"rendered":"CoffeShop cz. 3 &#8211; Kontrolery i CQRS"},"content":{"rendered":"\n<p><strong>R<\/strong>ozbudujemy nasze kontrolery o nast\u0119puj\u0105ce opcje: <\/p>\n\n\n\n<ul><li><a href=\"#Create-Order\">dodawania nowych zam\u00f3wie\u0144,<\/a><\/li><li><a href=\"#Update-Order\">aktualizacji stanu zam\u00f3wienia.<\/a><\/li><li><a href=\"#Detail-Order\">poszczeg\u00f3lnego zam\u00f3wienia,<\/a><\/li><li><a href=\"#All-Order\">wy\u015bwietlania listy zam\u00f3wie\u0144,<\/a><\/li><\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">0. Na pocz\u0105tek stworzymy kontroler:<\/h5>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">namespace Presentation.Controllers\n{\n    public class OrdersController : BaseController\n    {\n        [HttpGet]\n        public async Task&lt;OrdersListVm&gt; GetAll()\n        {\n            return await Mediator.Send(new GetAllOrdersQuery());\n        }\n\n        [HttpGet(\"{id}\")]\n        public async Task&lt;OrderDetailVm&gt; GetById(int id)\n        {\n            return await Mediator.Send(new GetOrderDetailQuery() { Id = id });\n        }\n\n        [HttpPost]\n        public async Task&lt;int&gt; Create([FromBody] CreateOrderCommand command)\n        {\n            return await Mediator.Send(command);\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ Update Order Status by one step\n        \/\/\/ &lt;\/summary&gt;\n        [HttpPut(\"{id}\")]\n        public async Task&lt;Unit&gt; UpdateStatus(int id)\n        {\n            return await Mediator.Send(new UpdateOrderStatusCommand() { OrderId = id });\n        }\n    }\n}\n<\/pre>\n\n\n\n<p>Doda\u0142em nad ostatni\u0105 metod\u0105 komentarz kt\u00f3rzy b\u0119dzie wy\u015bwietlony w Swagger po wcze\u015bniejszej konfiguracji. <br>W <em>Startup.cs<\/em> w metodzie <em>ConfigureServices<\/em> dodajemy pod\u015bwietlone linijki. Dodatkowo mo\u017cemy doda\u0107 opcje \u017ceby dla naszego <em>enum OrderStatus <\/em>pola by\u0142y nie pokazywane w Swaggerze jako inty tylko jako stringi.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">            #region Swagger \n            services.AddSwaggerGen(c =&gt;\n            {\n                c.SwaggerDoc(\"v1\", new OpenApiInfo\n                {\n                    Version = \"v1\",\n                    Title = \"CoffeShop API\",\n                    Description = \"*description*\",\n                });\n\n\n                var xmlFile = $\"{Assembly.GetExecutingAssembly().GetName().Name}.xml\";\n\n                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);\n\n                c.IncludeXmlComments(xmlPath);\n            });\n            #endregion\n            \n            services.AddControllers()\n                .AddJsonOptions(options =&gt;\n             options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));\n            <\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h5 class=\"wp-block-heading\" id=\"Create-Order\">1. Dodamy klase obs\u0142uguj\u0105c\u0105 sk\u0142adanie nowych zam\u00f3wie\u0144. <\/h5>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">    public class CreateOrderCommand : IRequest&lt;int&gt;\n    {\n        public IEnumerable&lt;OrderDetailOtd&gt; Details { get; set; }\n\n        public class CreateOrderCommandHandler : IRequestHandler&lt;CreateOrderCommand, int&gt;\n        {\n            public readonly IContext _context;\n            public readonly IMapper _mapper;\n\n            public CreateOrderCommandHandler(IContext context, IMapper mapper)\n                =&gt; (_context, _mapper) = (context, mapper);\n\n            public async Task&lt;int&gt; Handle(CreateOrderCommand request, CancellationToken cancellationToken)\n            {\n               var details = request.Details.Select(o =&gt; new OrderDetail\n                {\n                    Quantity = o.Quantity,\n                    Product = _context.Products.First(p =&gt; p.Id == o.ProductId),\n                    AdditionalInfo = o.AdditionalInfo\n                }).ToList();\n\n                foreach (var detail in details)\n                {\n                    detail.UnitPrice = detail.Product.Price * detail.Quantity;\n                    detail.UnitTimeToPrepare = detail.Product.TimeToPrepare * detail.Quantity;\n                }\n\n                var order = new Order\n                {\n                    Status = OrderStatus.NotStarted,\n                    OrderPlaced = DateTime.UtcNow,\n                    OrderCompleted = null,\n                }.AddOrderDetails(details);\n                \n                var entry = _context.Orders.Add(order);\n\n                await _context.SaveChangesAsync();\n\n                return entry.Entity.Id;\n            }\n        }\n    }\n\n    public class OrderDetailOtd\n    {\n        public int ProductId { get; set; }\n        public int Quantity { get; set; }\n        public string AdditionalInfo { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>Nie mia\u0142em pomys\u0142u jak nazwa\u0107 klase kt\u00f3ra ma by\u0107 naszym typem generycznym dla IEnumerable wi\u0119c postawi\u0142em na ko\u0144c\u00f3wke Otd, bo tak jak mamy klasy Dto czyli Data-To-Object kt\u00f3re u\u017cywamy do przekazania u\u017cytkownikowi tylko cz\u0119\u015bci informacji z elementu bazy tak pomy\u015bla\u0142em \u017ce co\u015b co ma dzia\u0142a\u0107 odwrotnie b\u0119dzie w\u0142a\u015bnie Otd Object-To-Data. \ud83e\udd14<\/p>\n\n\n\n<p>Sprawdzimy sobie w Swagger jak to dzia\u0142a. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"667\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-10.png?w=768\" alt=\"\" class=\"wp-image-167\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-10.png 768w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-10-300x261.png 300w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-11.png?w=770\" alt=\"\" class=\"wp-image-168\" width=\"770\" height=\"586\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-11.png 770w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-11-300x228.png 300w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-11-768x584.png 768w\" sizes=\"auto, (max-width: 770px) 100vw, 770px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Widzimy \u017ce wszystko dzia\u0142a, mo\u017cemy nawet sprawdzi\u0107 w bazie jak to wygl\u0105da.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"818\" height=\"617\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-12.png?w=818\" alt=\"\" class=\"wp-image-170\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-12.png 818w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-12-300x226.png 300w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-12-768x579.png 768w\" sizes=\"auto, (max-width: 818px) 100vw, 818px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h5 class=\"wp-block-heading\" id=\"Update-Order\">2. Nast\u0119pnie dodamy opcje aktualizacji statusu zam\u00f3wienia.<\/h5>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">namespace Application.Orders.Command.UpdateOrderStatusCommand\n{\n    public class UpdateOrderStatusCommand : IRequest\n    {\n        public int OrderId { get; set; }\n        \n        public class UpdateOrderStatusCommandHandler : IRequestHandler&lt;UpdateOrderStatusCommand&gt;\n        {\n            public readonly IContext _context;\n\n            public UpdateOrderStatusCommandHandler(IContext context)\n                =&gt; (_context) = (context);\n\n            public async Task&lt;Unit&gt; Handle(UpdateOrderStatusCommand request, CancellationToken cancellationToken)\n            {\n                var order = _context.Orders.Find(request.OrderId);\n\n                if (order == null)\n                {\n                    return Unit.Value;\n                }\n\n                if (order.Status != OrderStatus.Completed)\n                {\n                    order.Status += 1;\n\n\n                    if (order.Status == OrderStatus.Completed)\n                    {\n                        order.OrderCompleted = DateTime.UtcNow;\n                    }\n\n                    _context.Orders.Update(order);\n                }\n\n                await _context.SaveChangesAsync();\n\n                return Unit.Value;\n            }\n        }\n    }\n}<\/pre>\n\n\n\n<p>Program sprawdza najpierw czy zam\u00f3wienie istnieje, je\u015bli tak sprawdza czy nie ma ju\u017c statusu uko\u0144czonego i dopiero wtedy modyfikuje go o jeden krok. Je\u015bli zam\u00f3wienie mia\u0142o stan jeden przed <em>Completed <\/em>i ma zosta\u0107 zakualizowane zostaje do niego dodana godzina skompletowania.<\/p>\n\n\n\n<p>Testujemy przez swagger podaj\u0105c <em>Id <\/em>zam\u00f3wienia kt\u00f3rego stan chcemy zaktualizowa\u0107:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"773\" height=\"793\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-13.png?w=773\" alt=\"\" class=\"wp-image-173\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-13.png 773w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-13-292x300.png 292w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-13-768x788.png 768w\" sizes=\"auto, (max-width: 773px) 100vw, 773px\" \/><\/figure><\/div>\n\n\n\n<p>I sprawdzamy w bazie:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"456\" height=\"232\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-14.png?w=456\" alt=\"\" class=\"wp-image-175\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-14.png 456w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-14-300x153.png 300w\" sizes=\"auto, (max-width: 456px) 100vw, 456px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h6 class=\"wp-block-heading\" id=\"Detail-Order\">3. Nastepnie dodamy opcje sprawdzenia szczeg\u00f3\u0142\u00f3w pojedynczego zam\u00f3wienia.<\/h6>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">namespace Application.Orders.Query.GetOrderQuery\n{\n    public class GetOrderDetailQuery : IRequest&lt;OrderDetailVm&gt;\n    {\n        public int Id { get; set; }\n\n        public class GetOrderDetailQueryHandler : IRequestHandler&lt;GetOrderDetailQuery, OrderDetailVm&gt;\n        {\n            public readonly IContext _context;\n            public readonly IMapper _mapper;\n\n            private const int TIP_PERCENTAGE = 10;\n            private const int TIP_THRESHOLD = 5;\n\n            public GetOrderDetailQueryHandler(IContext context, IMapper mapper)\n                =&gt; (_context, _mapper) = (context, mapper);\n\n            public async Task&lt;OrderDetailVm&gt; Handle(GetOrderDetailQuery request, CancellationToken cancellationToken)\n            {\n                var order = _context.Orders.AsNoTracking()\n                    .Include(order =&gt; order.OrderDetails)\n                    .First(order =&gt; order.Id == request.Id);\n\n                var dto = order.OrderDetails\n                    .Select(d =&gt; new OrderDetailDto \n                    { \n                        ProductName = _context.Products.First(p =&gt; p.Id == d.ProductId).Name,\n                        UnitPrice = d.UnitPrice,\n                        UnitTimeToPrepare = d.UnitTimeToPrepare,\n                        Quantity = d.Quantity\n                    });\n\n                var vm = new OrderDetailVm\n                {\n                    OrderId = request.Id,\n                    Status = order.Status,\n                    Details = dto,\n                    TotalPrice = order.OrderDetails.Select(d =&gt; d.UnitPrice).Sum(),\n                    TotalTimeToPrepare = order.OrderDetails.Select(d =&gt; d.UnitTimeToPrepare).Sum(),\n                    TipPercentage = 0,\n                };\n\n                var quantity = dto.Select(o =&gt; o.Quantity).Sum();\n\n                if (quantity &gt; TIP_THRESHOLD)\n                {\n                    vm.TipPercentage = TIP_PERCENTAGE;\n                    vm.TotalPrice = vm.TotalPrice * (1 + (vm.TipPercentage \/ 100m));\n                }\n\n                return vm;\n            }\n        }\n    }\n\n    public class OrderDetailDto : IMapFrom&lt;OrderDetail&gt;\n    {\n        public string ProductName { get; set; }\n        public int Quantity { get; set; }\n        public decimal UnitPrice { get; set; }\n        public int UnitTimeToPrepare { get; set; }\n\n\n        public void Mapping(Profile profile)\n        {\n            profile.CreateMap&lt;OrderDetail, OrderDetailDto&gt;()\n                .ForMember(vm =&gt; vm.ProductName, opt =&gt; opt.MapFrom(s =&gt; s.Product.Name))\n                .ForMember(vm =&gt; vm.Quantity, opt =&gt; opt.MapFrom(s =&gt; s.Quantity))\n                .ForMember(vm =&gt; vm.UnitPrice, opt =&gt; opt.MapFrom(s =&gt; s.UnitPrice))\n                .ForMember(vm =&gt; vm.UnitTimeToPrepare, opt =&gt; opt.MapFrom(s =&gt; s.UnitTimeToPrepare));\n        }\n    }\n\n    public class OrderDetailVm\n    {\n        public int OrderId { get; set; }\n        public decimal TotalPrice { get; set; }\n        public int TotalTimeToPrepare { get; set; }\n        public int TipPercentage { get; set; }\n\n        public OrderStatus Status { get; set; }\n        public IEnumerable&lt;OrderDetailDto&gt; Details { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>Jak wynika z powy\u017cszego kodu dla zam\u00f3wie\u0144 powy\u017cej 5 sztuk b\u0119dzie doliczony napiwek w wysoko\u015bci 10% od ca\u0142kowietej kwoty zam\u00f3wienia. Zeby to przestestowa\u0107 dodam nowe zam\u00f3wienie w postaci:<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">{\n  \"details\": [\n    {\n      \"productId\": 3,\n      \"quantity\": 2,\n      \"additionalInfo\": \"test\"\n    },\n    {\n      \"productId\": 7,\n      \"quantity\": 4,\n      \"additionalInfo\": \"test\"\n    }\n  ]\n}<\/pre>\n\n\n\n<p>Pobierzemy teraz szczeg\u00f3\u0142y tego zam\u00f3wienia:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"767\" height=\"636\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-16.png?w=767\" alt=\"\" class=\"wp-image-197\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-16.png 767w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-16-300x249.png 300w\" sizes=\"auto, (max-width: 767px) 100vw, 767px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"770\" height=\"520\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-17.png?w=770\" alt=\"\" class=\"wp-image-198\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-17.png 770w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-17-300x203.png 300w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-17-768x519.png 768w\" sizes=\"auto, (max-width: 770px) 100vw, 770px\" \/><\/figure><\/div>\n\n\n\n<p>Widzimy do ceny zam\u00f3wienie zosta\u0142o doliczone 10% napiwku na co wskazuje tak\u017ce pole <em>tipPercentage<\/em>, dostajemy tak\u017ce informacje o ca\u0142kowitym czasie na przygotowanie ca\u0142ego zam\u00f3wienia.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\" id=\"All-Order\">4. Pobranie uproszczonej listy wszystkich zam\u00f3wie\u0144. <\/h5>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">namespace Application.Orders.Query.GetAllOrdersQuery\n{\n    public class GetAllOrdersQuery : IRequest&lt;OrdersListVm&gt;\n    {\n        public class GetAllOrdersQueryHandler : IRequestHandler&lt;GetAllOrdersQuery, OrdersListVm&gt;\n        {\n            private readonly IContext _context;\n            private readonly IMapper _mapper;\n\n            public GetAllOrdersQueryHandler(IContext context, IMapper mapper)\n                =&gt; (_context, _mapper) = (context, mapper);\n\n            public async Task&lt;OrdersListVm&gt; Handle(GetAllOrdersQuery request, CancellationToken cancellationToken)\n            {\n                var orders = await _context.Orders.AsNoTracking()\n                    .ProjectTo&lt;OrderDto&gt;(_mapper.ConfigurationProvider)\n                    .ToListAsync(cancellationToken);\n\n                var vm = new OrdersListVm\n                {\n                    Orders = orders\n                };\n\n                return vm;\n            }\n        }\n    }\n\n    public class OrderDto : IMapFrom&lt;Order&gt;\n    {\n        public int Id { get; set; }\n        public DateTime OrderPlaced { get; set; }\n        public DateTime? OrderCompleted { get; set; }\n        public OrderStatus Status { get; set; }\n\n        public void Mapping(Profile profile)\n        {\n            profile.CreateMap&lt;Order, OrderDto&gt;()\n                .ForMember(vm =&gt; vm.Id, opt =&gt; opt.MapFrom(s =&gt; s.Id))\n                .ForMember(vm =&gt; vm.Status, opt =&gt; opt.MapFrom(s =&gt; s.Status))\n                .ForMember(vm =&gt; vm.OrderPlaced, opt =&gt; opt.MapFrom(s =&gt; s.OrderPlaced))\n                .ForMember(vm =&gt; vm.OrderCompleted, opt =&gt; opt.MapFrom(s =&gt; s.OrderCompleted))\n                .ForSourceMember(o =&gt; o.OrderDetails, opt =&gt; opt.DoNotValidate());\n        }\n    }\n\n    public class OrdersListVm\n    {\n        public IList&lt;OrderDto&gt; Orders { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>Dzi\u0119ki dodaniu opcji <em>AsNoTracking( )<\/em> EF Core automatycznie zakoczy transakcje z baz bez oczekiwania na jakiekolwiek zmiany. <\/p>\n\n\n\n<p>Testujemy w Swaggerze.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"782\" height=\"837\" src=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-18.png?w=782\" alt=\"\" class=\"wp-image-203\" srcset=\"https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-18.png 782w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-18-280x300.png 280w, https:\/\/tymejczyk.net\/wp-content\/uploads\/2020\/09\/image-18-768x822.png 768w\" sizes=\"auto, (max-width: 782px) 100vw, 782px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Widzimy dostajemy uproszczon\u0105 mocno liste z kt\u00f3rej wiemy jedynie o kt\u00f3rej godzinie zosta\u0142o z\u0142o\u017cone i skompletowane zam\u00f3wienie.<br><\/p>\n\n\n\n<p>Aby dowiedzie\u0107 si\u0119 o wadach i zaletach CQRS polecam: <a rel=\"noreferrer noopener\" href=\"https:\/\/www.programmingwithwolfgang.com\/cqrs-in-asp-net-core-3-1\/\" target=\"_blank\">https:\/\/www.programmingwithwolfgang.com\/cqrs-in-asp-net-core-3-1\/<\/a><\/p>\n\n\n\n<p>Ca\u0142y kod zamieszczam na github:&nbsp;<a href=\"https:\/\/github.com\/MichaelStett\/CoffeShop\">https:\/\/github.com\/MichaelStett\/CoffeShop<\/a><\/p>\n\n\n\n<p>Dzi\u0119kuje za Twoj\u0105 uwag\u0119 i do nast\u0119pnego&nbsp;\ud83d\ude00<\/p>\n\n\n\n<p><br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rozbudujemy nasze kontrolery o nast\u0119puj\u0105ce opcje: dodawania nowych zam\u00f3wie\u0144, aktualizacji stanu zam\u00f3wienia. poszczeg\u00f3lnego zam\u00f3wienia, wy\u015bwietlania listy zam\u00f3wie\u0144, 0. Na pocz\u0105tek stworzymy kontroler: Doda\u0142em nad ostatni\u0105 metod\u0105 komentarz kt\u00f3rzy b\u0119dzie wy\u015bwietlony w Swagger po wcze\u015bniejszej konfiguracji. W Startup.cs w metodzie ConfigureServices dodajemy pod\u015bwietlone linijki. Dodatkowo mo\u017cemy doda\u0107 opcje \u017ceby dla naszego enum OrderStatus pola by\u0142y nie [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":165,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-141","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-project-coffeshop"],"_links":{"self":[{"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/posts\/141","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/comments?post=141"}],"version-history":[{"count":0,"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/posts\/141\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/media\/165"}],"wp:attachment":[{"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/media?parent=141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/categories?post=141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tymejczyk.net\/index.php\/wp-json\/wp\/v2\/tags?post=141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}