Files
go-cart-actor/internal/ucp/handler.go
T
mats c0c5a8bc0f
Build and Publish / BuildAndDeployArm64 (push) Failing after 5s
Build and Publish / BuildAndDeployAmd64 (push) Failing after 2s
update customer
2026-06-25 21:09:58 +02:00

175 lines
7.5 KiB
Go

package ucp
import "net/http"
// ---------------------------------------------------------------------------
// Order HTTP handler mounting
// ---------------------------------------------------------------------------
// OrderHandler returns an http.Handler that routes UCP order REST endpoints.
// Mount it under any prefix (e.g. /ucp/v1) in a ServeMux:
//
// mux.Handle("/ucp/v1/orders", ucp.OrderHandler(pool))
// mux.Handle("/ucp/v1/orders/", ucp.OrderHandler(pool))
//
// To sign responses with RFC 9421 HTTP Message Signatures, wrap with WithSigning:
//
// mux.Handle("/ucp/v1/orders", ucp.WithSigning(ucp.OrderHandler(pool), signer))
func OrderHandler(applier OrderReadApplier) http.Handler {
s := NewOrderServer(applier)
mux := http.NewServeMux()
mux.HandleFunc("GET /{id}", s.handleGetOrder)
mux.HandleFunc("POST /{id}/cancel", s.handleCancelOrder)
mux.HandleFunc("POST /{id}/fulfillments", s.handleCreateFulfillment)
mux.HandleFunc("POST /{id}/returns", s.handleRequestReturn)
mux.HandleFunc("POST /{id}/refunds", s.handleIssueRefund)
return withUCPAgent(withJSONContentType(mux))
}
// ---------------------------------------------------------------------------
// Cart HTTP handler mounting
// ---------------------------------------------------------------------------
// CartHandler returns an http.Handler that routes UCP cart REST endpoints.
// Mount it under any prefix (e.g. /ucp/v1) in a ServeMux:
//
// mux.Handle("/ucp/v1/carts", ucp.CartHandler(pool))
// mux.Handle("/ucp/v1/carts/", ucp.CartHandler(pool))
//
// To sign responses with RFC 9421 HTTP Message Signatures, wrap with WithSigning:
//
// mux.Handle("/ucp/v1/carts", ucp.WithSigning(ucp.CartHandler(pool), signer))
func CartHandler(applier CartApplier) http.Handler {
s := NewCartServer(applier)
mux := http.NewServeMux()
mux.HandleFunc("POST /", s.handleCreateCart)
mux.HandleFunc("GET /{id}", s.handleGetCart)
mux.HandleFunc("PUT /{id}", s.handleUpdateCart)
mux.HandleFunc("POST /{id}/cancel", s.handleCancelCart)
return withUCPAgent(withJSONContentType(mux))
}
// ---------------------------------------------------------------------------
// Checkout HTTP handler mounting
// ---------------------------------------------------------------------------
// CheckoutHandler returns an http.Handler that routes UCP checkout endpoints.
// An optional OrderApplier can be provided for real order creation on complete.
//
// mux.Handle("/ucp/v1/checkout-sessions", ucp.CheckoutHandler(pool))
// mux.Handle("/ucp/v1/checkout-sessions/", ucp.CheckoutHandler(pool, orderSvc))
//
// To sign responses with RFC 9421 HTTP Message Signatures, wrap with WithSigning:
//
// mux.Handle("/ucp/v1/checkout-sessions", ucp.WithSigning(ucp.CheckoutHandler(pool), signer))
func CheckoutHandler(applier CheckoutApplier, orderSvc ...OrderApplier) http.Handler {
s := NewCheckoutServer(applier, orderSvc...)
mux := http.NewServeMux()
mux.HandleFunc("POST /", s.handleCreateCheckout)
mux.HandleFunc("GET /{id}", s.handleGetCheckout)
mux.HandleFunc("PUT /{id}", s.handleUpdateCheckout)
mux.HandleFunc("POST /{id}/complete", s.handleCompleteCheckout)
mux.HandleFunc("POST /{id}/cancel", s.handleCancelCheckout)
return withUCPAgent(withJSONContentType(mux))
}
// ---------------------------------------------------------------------------
// Customer HTTP handler mounting
// ---------------------------------------------------------------------------
// CustomerHandler returns an http.Handler that routes UCP customer/profile
// REST endpoints. Mount it under any prefix (e.g. /ucp/v1) in a ServeMux:
//
// mux.Handle("/ucp/v1/customers", ucp.CustomerHandler(pool))
// mux.Handle("/ucp/v1/customers/", ucp.CustomerHandler(pool))
//
// To sign responses with RFC 9421 HTTP Message Signatures, wrap with WithSigning:
//
// mux.Handle("/ucp/v1/customers", ucp.WithSigning(ucp.CustomerHandler(pool), signer))
func CustomerHandler(applier ProfileApplier) http.Handler {
s := NewCustomerServer(applier)
mux := http.NewServeMux()
mux.HandleFunc("POST /", s.handleCreateCustomer)
mux.HandleFunc("GET /{id}", s.handleGetCustomer)
mux.HandleFunc("PUT /{id}", s.handleUpdateCustomer)
mux.HandleFunc("POST /{id}/addresses", s.handleAddAddress)
mux.HandleFunc("PUT /{id}/addresses/{addressId}", s.handleUpdateAddress)
mux.HandleFunc("DELETE /{id}/addresses/{addressId}", s.handleRemoveAddress)
return withUCPAgent(withJSONContentType(mux))
}
// ---------------------------------------------------------------------------
// Combined handler for mounting all UCP endpoints under one prefix
// ---------------------------------------------------------------------------
// Options controls optional features of the combined handler.
type Options struct {
CheckoutApplier CheckoutApplier // when set, mounts /checkout-sessions
OrderApplier OrderApplier // optional order creation for complete endpoint
ProfileApplier ProfileApplier // when set, mounts /customers + enables identity linking
}
// Handler returns an http.Handler that serves all mounted UCP endpoints under
// a single prefix. Usage:
//
// mux.Handle("/ucp/v1/", ucp.Handler(pool, ucp.Options{
// CheckoutApplier: checkoutPool,
// ProfileApplier: profilePool,
// }))
func Handler(cartApplier CartApplier, opts Options) http.Handler {
mux := http.NewServeMux()
// Cart endpoints
cartSrv := NewCartServer(cartApplier)
if opts.ProfileApplier != nil {
cartSrv.SetProfileApplier(opts.ProfileApplier)
}
mux.HandleFunc("POST /carts", cartSrv.handleCreateCart)
mux.HandleFunc("GET /carts/{id}", cartSrv.handleGetCart)
mux.HandleFunc("PUT /carts/{id}", cartSrv.handleUpdateCart)
mux.HandleFunc("POST /carts/{id}/cancel", cartSrv.handleCancelCart)
// Checkout endpoints (optional)
if opts.CheckoutApplier != nil {
var orderOpts []OrderApplier
if opts.OrderApplier != nil {
orderOpts = []OrderApplier{opts.OrderApplier}
}
checkoutSrv := NewCheckoutServer(opts.CheckoutApplier, orderOpts...)
if opts.ProfileApplier != nil {
checkoutSrv.SetProfileApplier(opts.ProfileApplier)
}
mux.HandleFunc("POST /checkout-sessions", checkoutSrv.handleCreateCheckout)
mux.HandleFunc("GET /checkout-sessions/{id}", checkoutSrv.handleGetCheckout)
mux.HandleFunc("PUT /checkout-sessions/{id}", checkoutSrv.handleUpdateCheckout)
mux.HandleFunc("POST /checkout-sessions/{id}/complete", checkoutSrv.handleCompleteCheckout)
mux.HandleFunc("POST /checkout-sessions/{id}/cancel", checkoutSrv.handleCancelCheckout)
}
// Customer endpoints (optional)
if opts.ProfileApplier != nil {
customerSrv := NewCustomerServer(opts.ProfileApplier)
mux.HandleFunc("POST /customers", customerSrv.handleCreateCustomer)
mux.HandleFunc("GET /customers/{id}", customerSrv.handleGetCustomer)
mux.HandleFunc("PUT /customers/{id}", customerSrv.handleUpdateCustomer)
mux.HandleFunc("POST /customers/{id}/addresses", customerSrv.handleAddAddress)
mux.HandleFunc("PUT /customers/{id}/addresses/{addressId}", customerSrv.handleUpdateAddress)
mux.HandleFunc("DELETE /customers/{id}/addresses/{addressId}", customerSrv.handleRemoveAddress)
}
return withUCPAgent(withJSONContentType(mux))
}
// withUCPAgent wraps a handler with UCP-Agent header parsing middleware.
func withUCPAgent(next http.Handler) http.Handler {
return WithUCPAgent(next)
}
// withJSONContentType is a middleware that ensures all responses have Content-Type: application/json.
func withJSONContentType(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
next.ServeHTTP(w, r)
})
}