diff --git a/cmd/backoffice/main.go b/cmd/backoffice/main.go new file mode 100644 index 0000000..1f2ab91 --- /dev/null +++ b/cmd/backoffice/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + // Your code here +} diff --git a/cmd/cart/main.go b/cmd/cart/main.go index 398a564..8135bce 100644 --- a/cmd/cart/main.go +++ b/cmd/cart/main.go @@ -396,6 +396,8 @@ func main() { w.Write([]byte("1.0.0")) }) + mux.HandleFunc("/openapi.json", ServeEmbeddedOpenAPI) + sigs := make(chan os.Signal, 1) done := make(chan bool, 1) signal.Notify(sigs, syscall.SIGTERM) diff --git a/cmd/cart/openapi.json b/cmd/cart/openapi.json new file mode 100644 index 0000000..45a5f6f --- /dev/null +++ b/cmd/cart/openapi.json @@ -0,0 +1,677 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Cart Service API", + "description": "HTTP API for shopping cart operations (cookie-based or explicit id): retrieve cart, add/replace items, update quantity, manage deliveries.", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://cart.tornberg.me", + "description": "Production server" + }, + { + "url": "http://localhost:8080", + "description": "Local development (cart API mounted under /cart)" + } + ], + "paths": { + "/cart/": { + "get": { + "summary": "Get (or create) current cart (cookie based)", + "description": "Returns the current cart. If no cartid cookie is present a new cart is created and Set-Cart-Id response header plus a Set-Cookie header are sent.", + "responses": { + "200": { + "description": "Cart retrieved", + "headers": { + "Set-Cart-Id": { + "description": "Returned when a new cart was created this request", + "schema": { "type": "string" } + }, + "X-Pod-Name": { + "description": "Pod identifier serving the request", + "schema": { "type": "string" } + } + }, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "500": { "description": "Server error" } + } + }, + "post": { + "summary": "Add single SKU (body)", + "description": "Adds (or increases quantity of) a single SKU using request body.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AddRequest" } + } + } + }, + "responses": { + "200": { + "description": "Item added", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid request body" }, + "500": { "description": "Server error" } + } + }, + "put": { + "summary": "Change quantity of an item", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ChangeQuantity" } + } + } + }, + "responses": { + "200": { + "description": "Quantity updated", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid request body" }, + "500": { "description": "Server error" } + } + }, + "delete": { + "summary": "Clear cart cookie (logical cart reused only if referenced later)", + "description": "Removes the cartid cookie by expiring it. Does not mutate server-side cart state.", + "responses": { + "200": { "description": "Cookie cleared (empty body)" } + } + } + }, + "/cart/add/{sku}": { + "get": { + "summary": "Add a SKU (path)", + "description": "Adds a single SKU with implicit quantity 1. Country inferred from Host header (-se / -no).", + "parameters": [{ "$ref": "#/components/parameters/SkuParam" }], + "responses": { + "200": { + "description": "Item added", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "500": { "description": "Server error" } + } + } + }, + "/cart/add": { + "post": { + "summary": "Add multiple items (append)", + "description": "Adds multiple items to the cart without clearing existing contents.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SetCartItems" } + } + } + }, + "responses": { + "200": { + "description": "Items added", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/set": { + "post": { + "summary": "Replace cart contents", + "description": "Clears the cart first, then adds the provided items (idempotent with respect to target set).", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SetCartItems" } + } + } + }, + "responses": { + "200": { + "description": "Cart replaced", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/{itemId}": { + "delete": { + "summary": "Remove item by line id", + "parameters": [ + { + "name": "itemId", + "in": "path", + "required": true, + "schema": { "type": "integer", "format": "int64", "minimum": 0 }, + "description": "Internal cart line item identifier (not SKU)." + } + ], + "responses": { + "200": { + "description": "Item removed", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Bad id" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/delivery": { + "post": { + "summary": "Set (add) delivery", + "description": "Adds a delivery option referencing one or more line item ids.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SetDeliveryRequest" } + } + } + }, + "responses": { + "200": { + "description": "Delivery added/updated", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/delivery/{deliveryId}": { + "delete": { + "summary": "Remove delivery", + "parameters": [{ "$ref": "#/components/parameters/DeliveryIdParam" }], + "responses": { + "200": { + "description": "Delivery removed", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Bad id" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/delivery/{deliveryId}/pickupPoint": { + "put": { + "summary": "Set pickup point for delivery", + "parameters": [{ "$ref": "#/components/parameters/DeliveryIdParam" }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/PickupPoint" } + } + } + }, + "responses": { + "200": { + "description": "Pickup point set", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/byid/{id}": { + "get": { + "summary": "Get cart by explicit id", + "parameters": [{ "$ref": "#/components/parameters/CartIdParam" }], + "responses": { + "200": { + "description": "Cart retrieved", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid id" }, + "500": { "description": "Server error" } + } + }, + "post": { + "summary": "Add single SKU (body) by cart id", + "parameters": [{ "$ref": "#/components/parameters/CartIdParam" }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AddRequest" } + } + } + }, + "responses": { + "200": { + "description": "Item added", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + }, + "put": { + "summary": "Change quantity (by id variant)", + "parameters": [{ "$ref": "#/components/parameters/CartIdParam" }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ChangeQuantity" } + } + } + }, + "responses": { + "200": { + "description": "Quantity updated", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/byid/{id}/add/{sku}": { + "get": { + "summary": "Add SKU (path) by explicit cart id", + "parameters": [ + { "$ref": "#/components/parameters/CartIdParam" }, + { "$ref": "#/components/parameters/SkuParam" } + ], + "responses": { + "200": { + "description": "Item added", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid id/sku" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/byid/{id}/{itemId}": { + "delete": { + "summary": "Remove item (by id variant)", + "parameters": [ + { "$ref": "#/components/parameters/CartIdParam" }, + { + "name": "itemId", + "in": "path", + "required": true, + "schema": { "type": "integer", "format": "int64", "minimum": 0 } + } + ], + "responses": { + "200": { + "description": "Item removed", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid id" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/byid/{id}/delivery": { + "post": { + "summary": "Set delivery (by id variant)", + "parameters": [{ "$ref": "#/components/parameters/CartIdParam" }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SetDeliveryRequest" } + } + } + }, + "responses": { + "200": { + "description": "Delivery added/updated", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/byid/{id}/delivery/{deliveryId}": { + "delete": { + "summary": "Remove delivery (by id variant)", + "parameters": [ + { "$ref": "#/components/parameters/CartIdParam" }, + { "$ref": "#/components/parameters/DeliveryIdParam" } + ], + "responses": { + "200": { + "description": "Delivery removed", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid ids" }, + "500": { "description": "Server error" } + } + } + }, + "/cart/byid/{id}/delivery/{deliveryId}/pickupPoint": { + "put": { + "summary": "Set pickup point (by id variant)", + "parameters": [ + { "$ref": "#/components/parameters/CartIdParam" }, + { "$ref": "#/components/parameters/DeliveryIdParam" } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/PickupPoint" } + } + } + }, + "responses": { + "200": { + "description": "Pickup point updated", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CartGrain" } + } + } + }, + "400": { "description": "Invalid body" }, + "500": { "description": "Server error" } + } + } + }, + "/healthz": { + "get": { + "summary": "Liveness & capacity probe", + "responses": { + "200": { "description": "Healthy" }, + "500": { "description": "Unhealthy" } + } + } + }, + "/readyz": { + "get": { + "summary": "Readiness probe", + "responses": { + "200": { "description": "Ready" } + } + } + }, + "/livez": { + "get": { + "summary": "Liveness probe", + "responses": { + "200": { "description": "Alive" } + } + } + }, + "/version": { + "get": { + "summary": "Service version", + "responses": { + "200": { + "description": "Version string", + "content": { + "text/plain": { + "schema": { "type": "string", "example": "1.0.0" } + } + } + } + } + } + } + }, + "components": { + "parameters": { + "SkuParam": { + "name": "sku", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + "CartIdParam": { + "name": "id", + "in": "path", + "required": true, + "description": "Base62 encoded cart id", + "schema": { + "type": "string", + "pattern": "^[0-9A-Za-z]+$", + "minLength": 1 + } + }, + "DeliveryIdParam": { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { "type": "integer", "format": "int64", "minimum": 0 } + } + }, + "schemas": { + "CartGrain": { + "type": "object", + "description": "Cart aggregate (actor state)", + "properties": { + "id": { + "type": "string", + "description": "Cart id (base62 encoded uint64)" + }, + "items": { + "type": "array", + "items": { "$ref": "#/components/schemas/CartItem" } + }, + "totalPrice": { "type": "integer", "format": "int64" }, + "totalTax": { "type": "integer", "format": "int64" }, + "totalDiscount": { "type": "integer", "format": "int64" }, + "deliveries": { + "type": "array", + "items": { "$ref": "#/components/schemas/CartDelivery" } + }, + "processing": { "type": "boolean" }, + "paymentInProgress": { "type": "boolean" }, + "orderReference": { "type": "string" }, + "paymentStatus": { "type": "string" } + }, + "required": ["id", "items", "totalPrice", "totalTax", "totalDiscount"] + }, + "CartItem": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "itemId": { "type": "integer" }, + "parentId": { "type": "integer" }, + "sku": { "type": "string" }, + "name": { "type": "string" }, + "price": { "type": "integer", "format": "int64" }, + "totalPrice": { "type": "integer", "format": "int64" }, + "totalTax": { "type": "integer", "format": "int64" }, + "orgPrice": { "type": "integer", "format": "int64" }, + "stock": { + "type": "integer", + "description": "0=OutOfStock,1=LowStock,2=InStock" + }, + "qty": { "type": "integer" }, + "tax": { "type": "integer" }, + "taxRate": { "type": "integer" }, + "brand": { "type": "string" }, + "category": { "type": "string" }, + "category2": { "type": "string" }, + "category3": { "type": "string" }, + "category4": { "type": "string" }, + "category5": { "type": "string" }, + "disclaimer": { "type": "string" }, + "sellerId": { "type": "string" }, + "sellerName": { "type": "string" }, + "type": { "type": "string", "description": "Article type" }, + "image": { "type": "string" }, + "outlet": { "type": "string", "nullable": true }, + "storeId": { "type": "string", "nullable": true } + }, + "required": ["id", "sku", "name", "price", "qty", "tax"] + }, + "CartDelivery": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "provider": { "type": "string" }, + "price": { "type": "integer", "format": "int64" }, + "items": { + "type": "array", + "items": { "type": "integer" } + }, + "pickupPoint": { "$ref": "#/components/schemas/PickupPoint" } + }, + "required": ["id", "provider", "price", "items"] + }, + "PickupPoint": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string", "nullable": true }, + "address": { "type": "string", "nullable": true }, + "city": { "type": "string", "nullable": true }, + "zip": { "type": "string", "nullable": true }, + "country": { "type": "string", "nullable": true } + }, + "required": ["id"] + }, + "AddRequest": { + "type": "object", + "properties": { + "quantity": { + "type": "integer", + "format": "int32", + "minimum": 1, + "default": 1 + }, + "sku": { "type": "string" }, + "country": { + "type": "string", + "description": "Two-letter country code (inferred if omitted)" + }, + "storeId": { "type": "string", "nullable": true } + }, + "required": ["sku"] + }, + "ChangeQuantity": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Cart line item id" + }, + "quantity": { "type": "integer", "format": "int32", "minimum": 0 } + }, + "required": ["id", "quantity"] + }, + "Item": { + "type": "object", + "properties": { + "sku": { "type": "string" }, + "quantity": { "type": "integer", "minimum": 1 }, + "storeId": { "type": "string", "nullable": true } + }, + "required": ["sku", "quantity"] + }, + "SetCartItems": { + "type": "object", + "properties": { + "country": { "type": "string" }, + "items": { + "type": "array", + "items": { "$ref": "#/components/schemas/Item" }, + "minItems": 0 + } + }, + "required": ["items"] + }, + "SetDeliveryRequest": { + "type": "object", + "properties": { + "provider": { "type": "string" }, + "items": { + "type": "array", + "items": { "type": "integer", "format": "int64" }, + "description": "Line item ids served by this delivery" + }, + "pickupPoint": { "$ref": "#/components/schemas/PickupPoint" } + }, + "required": ["provider", "items"] + } + } + }, + "tags": [{ "name": "Cart" }, { "name": "Delivery" }, { "name": "System" }] +} diff --git a/cmd/cart/openapi_embed.go b/cmd/cart/openapi_embed.go new file mode 100644 index 0000000..2739496 --- /dev/null +++ b/cmd/cart/openapi_embed.go @@ -0,0 +1,69 @@ +package main + +import ( + "bytes" + "crypto/sha256" + _ "embed" + "encoding/hex" + "net/http" + "sync" +) + +// openapi_embed.go: Provides embedded OpenAPI spec and helper to mount handler. + +//go:embed openapi.json +var openapiJSON []byte + +var ( + openapiOnce sync.Once + openapiETag string +) + +// initOpenAPIMetadata computes immutable metadata for the embedded spec. +func initOpenAPIMetadata() { + sum := sha256.Sum256(openapiJSON) + openapiETag = `W/"` + hex.EncodeToString(sum[:8]) + `"` // weak ETag with first 8 bytes +} + +// ServeEmbeddedOpenAPI serves the embedded OpenAPI JSON spec at /openapi.json. +// It supports GET and HEAD and implements basic ETag caching. +func ServeEmbeddedOpenAPI(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet && r.Method != http.MethodHead { + w.Header().Set("Allow", "GET, HEAD") + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + + openapiOnce.Do(initOpenAPIMetadata) + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("ETag", openapiETag) + + if match := r.Header.Get("If-None-Match"); match != "" { + if bytes.Contains([]byte(match), []byte(openapiETag)) { + w.WriteHeader(http.StatusNotModified) + return + } + } + + if r.Method == http.MethodHead { + w.WriteHeader(http.StatusOK) + return + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write(openapiJSON) +} + +// Optional: function to access raw spec bytes programmatically. +func OpenAPISpecBytes() []byte { + return openapiJSON +} + +// Optional: function to access current ETag. +func OpenAPIETag() string { + openapiOnce.Do(initOpenAPIMetadata) + return openapiETag +} diff --git a/cmd/cart/pool-server.go b/cmd/cart/pool-server.go index 59f64b4..6d84e0f 100644 --- a/cmd/cart/pool-server.go +++ b/cmd/cart/pool-server.go @@ -33,7 +33,7 @@ func (s *PoolServer) ApplyLocal(id CartId, mutation ...proto.Message) (*CartGrai return s.Apply(uint64(id), mutation...) } -func (s *PoolServer) HandleGet(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) GetCartHandler(w http.ResponseWriter, r *http.Request, id CartId) error { grain, err := s.Get(uint64(id)) if err != nil { return err @@ -42,7 +42,7 @@ func (s *PoolServer) HandleGet(w http.ResponseWriter, r *http.Request, id CartId return s.WriteResult(w, grain) } -func (s *PoolServer) HandleAddSku(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) AddSkuToCartHandler(w http.ResponseWriter, r *http.Request, id CartId) error { sku := r.PathValue("sku") msg, err := GetItemAddMessage(sku, 1, getCountryFromHost(r.Host), nil) if err != nil { @@ -72,7 +72,7 @@ func (s *PoolServer) WriteResult(w http.ResponseWriter, result *CartGrain) error return err } -func (s *PoolServer) HandleDeleteItem(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) DeleteItemHandler(w http.ResponseWriter, r *http.Request, id CartId) error { itemIdString := r.PathValue("itemId") itemId, err := strconv.Atoi(itemIdString) @@ -92,7 +92,7 @@ type SetDeliveryRequest struct { PickupPoint *messages.PickupPoint `json:"pickupPoint,omitempty"` } -func (s *PoolServer) HandleSetDelivery(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) SetDeliveryHandler(w http.ResponseWriter, r *http.Request, id CartId) error { delivery := SetDeliveryRequest{} err := json.NewDecoder(r.Body).Decode(&delivery) @@ -110,7 +110,7 @@ func (s *PoolServer) HandleSetDelivery(w http.ResponseWriter, r *http.Request, i return s.WriteResult(w, data) } -func (s *PoolServer) HandleSetPickupPoint(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) SetPickupPointHandler(w http.ResponseWriter, r *http.Request, id CartId) error { deliveryIdString := r.PathValue("deliveryId") deliveryId, err := strconv.Atoi(deliveryIdString) @@ -137,7 +137,7 @@ func (s *PoolServer) HandleSetPickupPoint(w http.ResponseWriter, r *http.Request return s.WriteResult(w, reply) } -func (s *PoolServer) HandleRemoveDelivery(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) RemoveDeliveryHandler(w http.ResponseWriter, r *http.Request, id CartId) error { deliveryIdString := r.PathValue("deliveryId") deliveryId, err := strconv.Atoi(deliveryIdString) @@ -151,7 +151,7 @@ func (s *PoolServer) HandleRemoveDelivery(w http.ResponseWriter, r *http.Request return s.WriteResult(w, reply) } -func (s *PoolServer) HandleQuantityChange(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) QuantityChangeHandler(w http.ResponseWriter, r *http.Request, id CartId) error { changeQuantity := messages.ChangeQuantity{} err := json.NewDecoder(r.Body).Decode(&changeQuantity) if err != nil { @@ -196,7 +196,7 @@ func getMultipleAddMessages(items []Item, country string) []proto.Message { return msgs } -func (s *PoolServer) HandleSetCartItems(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) SetCartItemsHandler(w http.ResponseWriter, r *http.Request, id CartId) error { setCartItems := SetCartItems{} err := json.NewDecoder(r.Body).Decode(&setCartItems) if err != nil { @@ -214,7 +214,7 @@ func (s *PoolServer) HandleSetCartItems(w http.ResponseWriter, r *http.Request, return s.WriteResult(w, reply) } -func (s *PoolServer) HandleAddMultiple(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) AddMultipleItemHandler(w http.ResponseWriter, r *http.Request, id CartId) error { setCartItems := SetCartItems{} err := json.NewDecoder(r.Body).Decode(&setCartItems) if err != nil { @@ -228,7 +228,7 @@ func (s *PoolServer) HandleAddMultiple(w http.ResponseWriter, r *http.Request, i return s.WriteResult(w, reply) } -func (s *PoolServer) HandleAddRequest(w http.ResponseWriter, r *http.Request, id CartId) error { +func (s *PoolServer) AddSkuRequestHandler(w http.ResponseWriter, r *http.Request, id CartId) error { addRequest := messages.AddRequest{} err := json.NewDecoder(r.Body).Decode(&addRequest) if err != nil { @@ -447,28 +447,28 @@ func (s *PoolServer) Serve() *http.ServeMux { w.WriteHeader(http.StatusOK) }) - mux.HandleFunc("GET /", CookieCartIdHandler(s.ProxyHandler(s.HandleGet))) - mux.HandleFunc("GET /add/{sku}", CookieCartIdHandler(s.ProxyHandler(s.HandleAddSku))) - mux.HandleFunc("POST /add", CookieCartIdHandler(s.ProxyHandler(s.HandleAddMultiple))) - mux.HandleFunc("POST /", CookieCartIdHandler(s.ProxyHandler(s.HandleAddRequest))) - mux.HandleFunc("POST /set", CookieCartIdHandler(s.ProxyHandler(s.HandleSetCartItems))) - mux.HandleFunc("DELETE /{itemId}", CookieCartIdHandler(s.ProxyHandler(s.HandleDeleteItem))) - mux.HandleFunc("PUT /", CookieCartIdHandler(s.ProxyHandler(s.HandleQuantityChange))) + mux.HandleFunc("GET /", CookieCartIdHandler(s.ProxyHandler(s.GetCartHandler))) + mux.HandleFunc("GET /add/{sku}", CookieCartIdHandler(s.ProxyHandler(s.AddSkuToCartHandler))) + mux.HandleFunc("POST /add", CookieCartIdHandler(s.ProxyHandler(s.AddMultipleItemHandler))) + mux.HandleFunc("POST /", CookieCartIdHandler(s.ProxyHandler(s.AddSkuRequestHandler))) + mux.HandleFunc("POST /set", CookieCartIdHandler(s.ProxyHandler(s.SetCartItemsHandler))) + mux.HandleFunc("DELETE /{itemId}", CookieCartIdHandler(s.ProxyHandler(s.DeleteItemHandler))) + mux.HandleFunc("PUT /", CookieCartIdHandler(s.ProxyHandler(s.QuantityChangeHandler))) mux.HandleFunc("DELETE /", CookieCartIdHandler(s.ProxyHandler(s.RemoveCartCookie))) - mux.HandleFunc("POST /delivery", CookieCartIdHandler(s.ProxyHandler(s.HandleSetDelivery))) - mux.HandleFunc("DELETE /delivery/{deliveryId}", CookieCartIdHandler(s.ProxyHandler(s.HandleRemoveDelivery))) - mux.HandleFunc("PUT /delivery/{deliveryId}/pickupPoint", CookieCartIdHandler(s.ProxyHandler(s.HandleSetPickupPoint))) + mux.HandleFunc("POST /delivery", CookieCartIdHandler(s.ProxyHandler(s.SetDeliveryHandler))) + mux.HandleFunc("DELETE /delivery/{deliveryId}", CookieCartIdHandler(s.ProxyHandler(s.RemoveDeliveryHandler))) + mux.HandleFunc("PUT /delivery/{deliveryId}/pickupPoint", CookieCartIdHandler(s.ProxyHandler(s.SetPickupPointHandler))) //mux.HandleFunc("GET /checkout", CookieCartIdHandler(s.ProxyHandler(s.HandleCheckout))) //mux.HandleFunc("GET /confirmation/{orderId}", CookieCartIdHandler(s.ProxyHandler(s.HandleConfirmation))) - mux.HandleFunc("GET /byid/{id}", CartIdHandler(s.ProxyHandler(s.HandleGet))) - mux.HandleFunc("GET /byid/{id}/add/{sku}", CartIdHandler(s.ProxyHandler(s.HandleAddSku))) - mux.HandleFunc("POST /byid/{id}", CartIdHandler(s.ProxyHandler(s.HandleAddRequest))) - mux.HandleFunc("DELETE /byid/{id}/{itemId}", CartIdHandler(s.ProxyHandler(s.HandleDeleteItem))) - mux.HandleFunc("PUT /byid/{id}", CartIdHandler(s.ProxyHandler(s.HandleQuantityChange))) - mux.HandleFunc("POST /byid/{id}/delivery", CartIdHandler(s.ProxyHandler(s.HandleSetDelivery))) - mux.HandleFunc("DELETE /byid/{id}/delivery/{deliveryId}", CartIdHandler(s.ProxyHandler(s.HandleRemoveDelivery))) - mux.HandleFunc("PUT /byid/{id}/delivery/{deliveryId}/pickupPoint", CartIdHandler(s.ProxyHandler(s.HandleSetPickupPoint))) + mux.HandleFunc("GET /byid/{id}", CartIdHandler(s.ProxyHandler(s.GetCartHandler))) + mux.HandleFunc("GET /byid/{id}/add/{sku}", CartIdHandler(s.ProxyHandler(s.AddSkuToCartHandler))) + mux.HandleFunc("POST /byid/{id}", CartIdHandler(s.ProxyHandler(s.AddSkuRequestHandler))) + mux.HandleFunc("DELETE /byid/{id}/{itemId}", CartIdHandler(s.ProxyHandler(s.DeleteItemHandler))) + mux.HandleFunc("PUT /byid/{id}", CartIdHandler(s.ProxyHandler(s.QuantityChangeHandler))) + mux.HandleFunc("POST /byid/{id}/delivery", CartIdHandler(s.ProxyHandler(s.SetDeliveryHandler))) + mux.HandleFunc("DELETE /byid/{id}/delivery/{deliveryId}", CartIdHandler(s.ProxyHandler(s.RemoveDeliveryHandler))) + mux.HandleFunc("PUT /byid/{id}/delivery/{deliveryId}/pickupPoint", CartIdHandler(s.ProxyHandler(s.SetPickupPointHandler))) //mux.HandleFunc("GET /byid/{id}/checkout", CartIdHandler(s.ProxyHandler(s.HandleCheckout))) //mux.HandleFunc("GET /byid/{id}/confirmation", CartIdHandler(s.ProxyHandler(s.HandleConfirmation)))