Skip to main content

Basket API Reference

Complete REST API documentation for the Basket service endpoints.

Base URL

http://localhost:5001

Endpoints

GET /basket/

Retrieve a shopping cart for a specific user.

Parameters

NameTypeLocationRequiredDescription
userNamestringpathYesThe username identifying the basket

Response

Status Code: 200 OK Response Body:
{
  "cart": {
    "userName": "swn",
    "items": [
      {
        "quantity": 2,
        "color": "Red",
        "price": 950.00,
        "productId": "5334c996-8457-4cf0-815c-ed2b77c4ff61",
        "productName": "IPhone X"
      },
      {
        "quantity": 1,
        "color": "Blue",
        "price": 840.00,
        "productId": "c67d6323-e8b1-4bdf-9a75-b0d0d2e7e914",
        "productName": "Samsung 10"
      }
    ],
    "totalPrice": 2740.00
  }
}

Error Responses

Status Code: 400 Bad Request
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "Validation error message"
}
Status Code: 404 Not Found
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "status": 404,
  "detail": "Basket with UserName 'unknown' was not found."
}

Example Request

curl -X GET http://localhost:5001/basket/swn
// C# Example
var client = new HttpClient();
var response = await client.GetAsync("http://localhost:5001/basket/swn");
var basket = await response.Content.ReadFromJsonAsync<GetBasketResponse>();

POST /basket

Create or update a shopping cart. Automatically applies discounts via gRPC communication with Discount service.

Request Body

{
  "cart": {
    "userName": "swn",
    "items": [
      {
        "quantity": 2,
        "color": "Red",
        "price": 1000.00,
        "productId": "5334c996-8457-4cf0-815c-ed2b77c4ff61",
        "productName": "IPhone X"
      }
    ]
  }
}

Request Schema

{
  "type": "object",
  "properties": {
    "cart": {
      "type": "object",
      "required": ["userName", "items"],
      "properties": {
        "userName": {
          "type": "string",
          "description": "Username identifying the basket"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["quantity", "color", "price", "productId", "productName"],
            "properties": {
              "quantity": { "type": "integer" },
              "color": { "type": "string" },
              "price": { "type": "number" },
              "productId": { "type": "string", "format": "uuid" },
              "productName": { "type": "string" }
            }
          }
        }
      }
    }
  }
}

Response

Status Code: 201 Created Headers:
Location: /basket/swn
Response Body:
{
  "userName": "swn"
}

Discount Application

The service automatically applies discounts before storing:
  1. For each item in the cart, calls Discount.Grpc service
  2. Retrieves coupon for the product by name
  3. Deducts the discount amount from item price
  4. Stores the discounted prices
Implementation (StoreBasketHandler.cs:30-38):
private async Task DeductDiscount(ShoppingCart cart, CancellationToken cancellationToken)
{
    foreach (var item in cart.Items)
    {
        var coupon = await discountProto.GetDiscountAsync(
            new GetDiscountRequest { ProductName = item.ProductName }, 
            cancellationToken: cancellationToken);
        item.Price -= coupon.Amount;
    }
}

Validation Rules

  • Cart must not be null
  • Cart.UserName must not be empty

Error Responses

Status Code: 400 Bad Request
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "Cart": ["Cart can not be null"],
    "Cart.UserName": ["UserName is required"]
  }
}

Example Request

curl -X POST http://localhost:5001/basket \
  -H "Content-Type: application/json" \
  -d '{
    "cart": {
      "userName": "swn",
      "items": [
        {
          "quantity": 2,
          "color": "Red",
          "price": 1000.00,
          "productId": "5334c996-8457-4cf0-815c-ed2b77c4ff61",
          "productName": "IPhone X"
        }
      ]
    }
  }'
// C# Example
var request = new StoreBasketRequest(
    new ShoppingCart("swn")
    {
        Items = new List<ShoppingCartItem>
        {
            new ShoppingCartItem
            {
                Quantity = 2,
                Color = "Red",
                Price = 1000.00M,
                ProductId = Guid.Parse("5334c996-8457-4cf0-815c-ed2b77c4ff61"),
                ProductName = "IPhone X"
            }
        }
    });

var response = await client.PostAsJsonAsync("http://localhost:5001/basket", request);

DELETE /basket/

Delete a shopping cart for a specific user. Removes from both database and cache.

Parameters

NameTypeLocationRequiredDescription
userNamestringpathYesThe username identifying the basket to delete

Response

Status Code: 200 OK Response Body:
{
  "isSuccess": true
}

Validation Rules

  • UserName must not be empty

Error Responses

Status Code: 400 Bad Request
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "UserName": ["UserName is required"]
  }
}
Status Code: 404 Not Found
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "status": 404,
  "detail": "Basket with UserName 'unknown' was not found."
}

Example Request

curl -X DELETE http://localhost:5001/basket/swn
// C# Example
var response = await client.DeleteAsync("http://localhost:5001/basket/swn");
var result = await response.Content.ReadFromJsonAsync<DeleteBasketResponse>();

POST /basket/checkout

Checkout a shopping basket. Publishes checkout event to message broker and deletes the basket.

Request Body

{
  "basketCheckoutDto": {
    "userName": "swn",
    "customerId": "58c49479-ec65-4de2-86e7-033c546291aa",
    "totalPrice": 0,
    "firstName": "John",
    "lastName": "Doe",
    "emailAddress": "[email protected]",
    "addressLine": "123 Main St",
    "country": "USA",
    "state": "California",
    "zipCode": "90210",
    "cardName": "John Doe",
    "cardNumber": "1234567890123456",
    "expiration": "12/25",
    "cvv": "123",
    "paymentMethod": 1
  }
}

Request Schema

{
  "type": "object",
  "properties": {
    "basketCheckoutDto": {
      "type": "object",
      "required": ["userName", "customerId", "firstName", "lastName", "emailAddress"],
      "properties": {
        "userName": { "type": "string" },
        "customerId": { "type": "string", "format": "uuid" },
        "totalPrice": { "type": "number", "description": "Automatically calculated" },
        "firstName": { "type": "string" },
        "lastName": { "type": "string" },
        "emailAddress": { "type": "string", "format": "email" },
        "addressLine": { "type": "string" },
        "country": { "type": "string" },
        "state": { "type": "string" },
        "zipCode": { "type": "string" },
        "cardName": { "type": "string" },
        "cardNumber": { "type": "string" },
        "expiration": { "type": "string" },
        "cvv": { "type": "string" },
        "paymentMethod": { "type": "integer" }
      }
    }
  }
}

Response

Status Code: 200 OK Response Body:
{
  "isSuccess": true
}

Checkout Process

The checkout operation performs the following steps (CheckoutBasketHandler.cs:25-46):
  1. Retrieve Basket: Fetches existing basket with calculated total price
  2. Create Event: Maps checkout DTO to BasketCheckoutEvent
  3. Set Total: Adds calculated total price to event
  4. Publish Event: Sends event to RabbitMQ via MassTransit
  5. Delete Basket: Removes basket from storage and cache
public async Task<CheckoutBasketResult> Handle(CheckoutBasketCommand command, CancellationToken cancellationToken)
{
    var basket = await repository.GetBasket(command.BasketCheckoutDto.UserName, cancellationToken);
    if (basket == null)
    {
        return new CheckoutBasketResult(false);
    }

    var eventMessage = command.BasketCheckoutDto.Adapt<BasketCheckoutEvent>();
    eventMessage.TotalPrice = basket.TotalPrice;

    await publishEndpoint.Publish(eventMessage, cancellationToken);
    await repository.DeleteBasket(command.BasketCheckoutDto.UserName, cancellationToken);

    return new CheckoutBasketResult(true);
}

Event Publishing

The BasketCheckoutEvent triggers downstream processes:
  • Order creation in Ordering service
  • Payment processing
  • Inventory updates
  • Email notifications

Validation Rules

  • BasketCheckoutDto must not be null
  • BasketCheckoutDto.UserName must not be empty

Error Responses

Status Code: 400 Bad Request
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "BasketCheckoutDto": ["BasketCheckoutDto can't be null"],
    "BasketCheckoutDto.UserName": ["UserName is required"]
  }
}

Example Request

curl -X POST http://localhost:5001/basket/checkout \
  -H "Content-Type: application/json" \
  -d '{
    "basketCheckoutDto": {
      "userName": "swn",
      "customerId": "58c49479-ec65-4de2-86e7-033c546291aa",
      "firstName": "John",
      "lastName": "Doe",
      "emailAddress": "[email protected]",
      "addressLine": "123 Main St",
      "country": "USA",
      "state": "California",
      "zipCode": "90210",
      "cardName": "John Doe",
      "cardNumber": "1234567890123456",
      "expiration": "12/25",
      "cvv": "123",
      "paymentMethod": 1
    }
  }'
// C# Example
var checkoutRequest = new CheckoutBasketRequest(
    new BasketCheckoutDto
    {
        UserName = "swn",
        CustomerId = Guid.Parse("58c49479-ec65-4de2-86e7-033c546291aa"),
        FirstName = "John",
        LastName = "Doe",
        EmailAddress = "[email protected]",
        AddressLine = "123 Main St",
        Country = "USA",
        State = "California",
        ZipCode = "90210",
        CardName = "John Doe",
        CardNumber = "1234567890123456",
        Expiration = "12/25",
        CVV = "123",
        PaymentMethod = 1
    });

var response = await client.PostAsJsonAsync(
    "http://localhost:5001/basket/checkout", 
    checkoutRequest);

Health Check

GET /health

Check the health status of the Basket service and its dependencies.

Response

Status Code: 200 OK (Healthy) or 503 Service Unavailable (Unhealthy) Response Body:
{
  "status": "Healthy",
  "totalDuration": "00:00:00.0234567",
  "entries": {
    "npgsql": {
      "status": "Healthy",
      "duration": "00:00:00.0123456",
      "data": {}
    },
    "redis": {
      "status": "Healthy",
      "duration": "00:00:00.0098765",
      "data": {}
    }
  }
}

Example Request

curl -X GET http://localhost:5001/health

Common Response Headers

All responses include standard headers:
Content-Type: application/json; charset=utf-8
Date: Thu, 05 Mar 2026 12:00:00 GMT

Error Response Format

All errors follow RFC 7807 Problem Details specification:
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Error Title",
  "status": 400,
  "detail": "Detailed error message",
  "errors": {
    "FieldName": ["Error message for field"]
  }
}

Build docs developers (and LLMs) love