openmeter / api /v3 /handlers /features /create.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 4)
1f10f31 verified
Raw
History Blame Contribute Delete
2.93 kB
package features
import (
"context"
"fmt"
"net/http"
api "github.com/openmeterio/openmeter/api/v3"
"github.com/openmeterio/openmeter/api/v3/apierrors"
"github.com/openmeterio/openmeter/api/v3/request"
"github.com/openmeterio/openmeter/openmeter/meter"
"github.com/openmeterio/openmeter/openmeter/productcatalog/feature"
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
"github.com/openmeterio/openmeter/pkg/models"
)
type (
CreateFeatureRequest = feature.CreateFeatureInputs
CreateFeatureResponse = api.Feature
CreateFeatureHandler httptransport.Handler[CreateFeatureRequest, CreateFeatureResponse]
)
func (h *handler) CreateFeature() CreateFeatureHandler {
return httptransport.NewHandler(
func(ctx context.Context, r *http.Request) (CreateFeatureRequest, error) {
body := api.CreateFeatureRequest{}
if err := request.ParseBody(r, &body); err != nil {
return CreateFeatureRequest{}, err
}
ns, err := h.resolveNamespace(ctx)
if err != nil {
return CreateFeatureRequest{}, err
}
// Resolve and validate the meter reference.
var meterID *string
if body.Meter != nil {
if body.Meter.Id == "" {
return CreateFeatureRequest{}, models.NewGenericValidationError(
fmt.Errorf("meter id is required"),
)
}
m, err := h.meterService.GetMeterByIDOrSlug(ctx, meter.GetMeterInput{
Namespace: ns,
IDOrSlug: body.Meter.Id,
})
if err != nil {
return CreateFeatureRequest{}, err
}
meterID = &m.ID
// Validate meter filters.
if body.Meter.Filters != nil {
if err := validateMeterFilters(*body.Meter.Filters, m); err != nil {
return CreateFeatureRequest{}, err
}
}
}
return convertCreateRequestToDomain(ns, body, meterID)
},
func(ctx context.Context, req CreateFeatureRequest) (CreateFeatureResponse, error) {
created, err := h.connector.CreateFeature(ctx, req)
if err != nil {
return CreateFeatureResponse{}, err
}
return convertFeatureToAPI(created)
},
commonhttp.JSONResponseEncoderWithStatus[CreateFeatureResponse](http.StatusCreated),
httptransport.AppendOptions(
h.options,
httptransport.WithOperationName("create-feature"),
httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()),
httptransport.WithErrorEncoder(errorEncoder()),
)...,
)
}
// validateMeterFilters validates that filter keys exist in the meter's dimensions.
// The single-operator invariant on each filter value is enforced downstream by
// feature.MeterGroupByFilters.Validate.
func validateMeterFilters(filters map[string]api.QueryFilterStringMapItem, m meter.Meter) error {
for k := range filters {
if _, ok := m.GroupBy[k]; !ok {
return models.NewGenericValidationError(
fmt.Errorf("filter key %q is not a valid dimension of meter %q", k, m.Key),
)
}
}
return nil
}