From adde13384ad01d4ff38488aa5e6596b61158a008 Mon Sep 17 00:00:00 2001 From: Piumal Rathnayake Date: Wed, 15 Jul 2026 22:10:37 +0530 Subject: [PATCH 1/2] Change apiId to artifactId in create subscription payload --- platform-api/api/generated.go | 24 ++++----- .../internal/handler/subscription_handler.go | 54 +++++++++---------- platform-api/resources/openapi.yaml | 20 +++---- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/platform-api/api/generated.go b/platform-api/api/generated.go index fdba73390..556fb1d31 100644 --- a/platform-api/api/generated.go +++ b/platform-api/api/generated.go @@ -954,13 +954,13 @@ type CreateSubscriptionPlanRequestStatus string // CreateSubscriptionRequest defines model for CreateSubscriptionRequest. type CreateSubscriptionRequest struct { - // ApiId Handle (ID) of the artifact to subscribe to. Resolved against the table for the given kind. - ApiId string `binding:"required" json:"apiId" yaml:"apiId"` - // ApplicationId Handle (ID) of the application this subscription belongs to. Optional in token-based subscriptions. ApplicationId *string `json:"applicationId,omitempty" yaml:"applicationId,omitempty"` - // Kind Type of the artifact identified by apiId. Determines which artifact table apiId is resolved against. + // ArtifactId Handle (ID) of the artifact to subscribe to. Resolved against the table for the given kind. + ArtifactId string `binding:"required" json:"artifactId" yaml:"artifactId"` + + // Kind Type of the artifact identified by artifactId. Determines which artifact table artifactId is resolved against. Kind CreateSubscriptionRequestKind `binding:"required" json:"kind" yaml:"kind"` // Status Subscription status (default ACTIVE) @@ -973,7 +973,7 @@ type CreateSubscriptionRequest struct { SubscriptionPlanId *string `json:"subscriptionPlanId,omitempty" yaml:"subscriptionPlanId,omitempty"` } -// CreateSubscriptionRequestKind Type of the artifact identified by apiId. Determines which artifact table apiId is resolved against. +// CreateSubscriptionRequestKind Type of the artifact identified by artifactId. Determines which artifact table artifactId is resolved against. type CreateSubscriptionRequestKind string // CreateSubscriptionRequestStatus Subscription status (default ACTIVE) @@ -2334,12 +2334,12 @@ type SecurityConfig struct { // Subscription defines model for Subscription. type Subscription struct { - // ApiId Handle (ID) of the subscribed artifact - ApiId *string `json:"apiId,omitempty" yaml:"apiId,omitempty"` - // ApplicationId Handle (ID) of the application this subscription belongs to (optional for token-based subscriptions) - ApplicationId *string `json:"applicationId,omitempty" yaml:"applicationId,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" yaml:"createdAt,omitempty"` + ApplicationId *string `json:"applicationId,omitempty" yaml:"applicationId,omitempty"` + + // ArtifactId Handle (ID) of the subscribed artifact + ArtifactId *string `json:"artifactId,omitempty" yaml:"artifactId,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" yaml:"createdAt,omitempty"` // CreatedBy User identifier of the user who created this resource CreatedBy *string `json:"createdBy,omitempty" yaml:"createdBy,omitempty"` @@ -3143,8 +3143,8 @@ type ListSubscriptionPlansParams struct { // ListSubscriptionsParams defines parameters for ListSubscriptions. type ListSubscriptionsParams struct { - // ApiId Filter by API ID (UUID or handle) - ApiId *string `form:"apiId,omitempty" json:"apiId,omitempty" yaml:"apiId,omitempty"` + // ArtifactId Filter by artifact ID (UUID or handle) + ArtifactId *string `form:"artifactId,omitempty" json:"artifactId,omitempty" yaml:"artifactId,omitempty"` // SubscriberId Filter by subscriber ID SubscriberId *string `form:"subscriberId,omitempty" json:"subscriberId,omitempty" yaml:"subscriberId,omitempty"` diff --git a/platform-api/internal/handler/subscription_handler.go b/platform-api/internal/handler/subscription_handler.go index c5a15e992..af41faeef 100644 --- a/platform-api/internal/handler/subscription_handler.go +++ b/platform-api/internal/handler/subscription_handler.go @@ -58,7 +58,7 @@ func NewSubscriptionHandler(subscriptionService *service.SubscriptionService, su // CreateSubscriptionRequest is the body for POST /api/v0.9/subscriptions type CreateSubscriptionRequest struct { - APIID string `json:"apiId" binding:"required"` + ArtifactID string `json:"artifactId" binding:"required"` Kind string `json:"kind" binding:"required"` SubscriberID string `json:"subscriberId" binding:"required"` ApplicationID *string `json:"applicationId,omitempty"` @@ -78,8 +78,8 @@ func (h *SubscriptionHandler) CreateSubscription(w http.ResponseWriter, r *http. return apperror.ValidationFailed.Wrap(err, "Invalid request body"). WithLogMessage(fmt.Sprintf("invalid create subscription request body for org %s", orgId)) } - if req.APIID == "" { - return apperror.ValidationFailed.New("API ID is required") + if req.ArtifactID == "" { + return apperror.ValidationFailed.New("artifactId is required") } if req.SubscriberID == "" { return apperror.ValidationFailed.New("subscriberId is required") @@ -99,17 +99,17 @@ func (h *SubscriptionHandler) CreateSubscription(w http.ResponseWriter, r *http. if err != nil { return err } - sub, err := h.subscriptionService.CreateSubscription(req.APIID, req.Kind, orgId, req.SubscriberID, req.ApplicationID, req.SubscriptionPlanID, "", req.Status, actor) + sub, err := h.subscriptionService.CreateSubscription(req.ArtifactID, req.Kind, orgId, req.SubscriberID, req.ApplicationID, req.SubscriptionPlanID, "", req.Status, actor) if err != nil { var appErr *apperror.Error if errors.As(err, &appErr) { return err } - return serviceError(err, fmt.Sprintf("failed to create subscription for api %s in org %s", req.APIID, orgId)) + return serviceError(err, fmt.Sprintf("failed to create subscription for artifact %s in org %s", req.ArtifactID, orgId)) } resp, err := h.toSubscriptionResponse(sub, orgId) if err != nil { - return serviceError(err, fmt.Sprintf("failed to resolve subscription identity for api %s in org %s", req.APIID, orgId)) + return serviceError(err, fmt.Sprintf("failed to resolve subscription identity for artifact %s in org %s", req.ArtifactID, orgId)) } setLocation(w, "subscriptions", sub.UUID) httputil.WriteJSON(w, http.StatusCreated, resp) @@ -118,7 +118,7 @@ func (h *SubscriptionHandler) CreateSubscription(w http.ResponseWriter, r *http. // ListSubscriptions handles GET /api/v0.9/subscriptions func (h *SubscriptionHandler) ListSubscriptions(w http.ResponseWriter, r *http.Request) error { - apiId := r.URL.Query().Get("apiId") + artifactId := r.URL.Query().Get("artifactId") subscriberID := r.URL.Query().Get("subscriberId") applicationID := r.URL.Query().Get("applicationId") status := r.URL.Query().Get("status") @@ -129,9 +129,9 @@ func (h *SubscriptionHandler) ListSubscriptions(w http.ResponseWriter, r *http.R WithLogMessage("organization claim not found in token") } - var apiIDPtr, subscriberIDPtr, appIDPtr, statusPtr *string - if apiId != "" { - apiIDPtr = &apiId + var artifactIDPtr, subscriberIDPtr, appIDPtr, statusPtr *string + if artifactId != "" { + artifactIDPtr = &artifactId } if subscriberID != "" { subscriberIDPtr = &subscriberID @@ -148,34 +148,34 @@ func (h *SubscriptionHandler) ListSubscriptions(w http.ResponseWriter, r *http.R statusPtr = &status } limit, offset := parsePagination(r) - list, total, err := h.subscriptionService.ListSubscriptionsByFilters(orgId, apiIDPtr, subscriberIDPtr, appIDPtr, statusPtr, limit, offset) + list, total, err := h.subscriptionService.ListSubscriptionsByFilters(orgId, artifactIDPtr, subscriberIDPtr, appIDPtr, statusPtr, limit, offset) if err != nil { var appErr *apperror.Error if errors.As(err, &appErr) { return err } - return serviceError(err, fmt.Sprintf("failed to list subscriptions for api %s in org %s", apiId, orgId)) + return serviceError(err, fmt.Sprintf("failed to list subscriptions for artifact %s in org %s", artifactId, orgId)) } - // Bulk fetch API handles and plan names to avoid N+1 queries - apiUUIDSet := make(map[string]struct{}) + // Bulk fetch artifact handles and plan names to avoid N+1 queries + artifactUUIDSet := make(map[string]struct{}) planIDSet := make(map[string]struct{}) for _, sub := range list { if sub.ArtifactUUID != "" { - apiUUIDSet[sub.ArtifactUUID] = struct{}{} + artifactUUIDSet[sub.ArtifactUUID] = struct{}{} } if sub.SubscriptionPlanID != nil && *sub.SubscriptionPlanID != "" { planIDSet[*sub.SubscriptionPlanID] = struct{}{} } } - apiUUIDs := make([]string, 0, len(apiUUIDSet)) - for u := range apiUUIDSet { - apiUUIDs = append(apiUUIDs, u) + artifactUUIDs := make([]string, 0, len(artifactUUIDSet)) + for u := range artifactUUIDSet { + artifactUUIDs = append(artifactUUIDs, u) } planIDs := make([]string, 0, len(planIDSet)) for id := range planIDSet { planIDs = append(planIDs, id) } - artifactMetaMap, err := h.subscriptionService.GetArtifactMetadataMap(apiUUIDs, orgId) + artifactMetaMap, err := h.subscriptionService.GetArtifactMetadataMap(artifactUUIDs, orgId) if err != nil { return serviceError(err, fmt.Sprintf("failed to bulk fetch artifact metadata for list in org %s", orgId)) } @@ -326,10 +326,10 @@ func (h *SubscriptionHandler) RegisterRoutes(mux *http.ServeMux) { } func (h *SubscriptionHandler) toSubscriptionResponse(sub *model.Subscription, orgId string) (map[string]any, error) { - // apiId in response should be the handle (e.g. "samp1"), not the internal UUID - apiIdForResponse, kind := h.subscriptionService.ResolveArtifactHandleAndKind(sub.ArtifactUUID, orgId) - if apiIdForResponse == "" { - apiIdForResponse = sub.ArtifactUUID // fallback to UUID + // artifactId in response should be the handle (e.g. "samp1"), not the internal UUID + artifactIdForResponse, kind := h.subscriptionService.ResolveArtifactHandleAndKind(sub.ArtifactUUID, orgId) + if artifactIdForResponse == "" { + artifactIdForResponse = sub.ArtifactUUID // fallback to UUID } createdBy, err := h.identity.SubForUUID(sub.CreatedBy) if err != nil { @@ -341,7 +341,7 @@ func (h *SubscriptionHandler) toSubscriptionResponse(sub *model.Subscription, or } resp := map[string]any{ "id": sub.UUID, - "apiId": apiIdForResponse, + "artifactId": artifactIdForResponse, "subscriberId": sub.SubscriberID, "organizationId": h.subscriptionService.ResolveOrgHandle(sub.OrganizationUUID), "status": string(sub.Status), @@ -375,11 +375,11 @@ func (h *SubscriptionHandler) toSubscriptionResponse(sub *model.Subscription, or // toSubscriptionResponseWithMaps builds a subscription response using pre-fetched lookup maps. // Used by ListSubscriptions to avoid N+1 queries. func (h *SubscriptionHandler) toSubscriptionResponseWithMaps(sub *model.Subscription, orgId string, artifactMetaMap map[string]*model.APIMetadata, planNameMap map[string]string, createdByMap map[string]string) map[string]any { - apiIdForResponse := sub.ArtifactUUID // fallback to UUID + artifactIdForResponse := sub.ArtifactUUID // fallback to UUID var kind string if meta := artifactMetaMap[sub.ArtifactUUID]; meta != nil { if meta.Handle != "" { - apiIdForResponse = meta.Handle + artifactIdForResponse = meta.Handle } kind = meta.Kind } @@ -389,7 +389,7 @@ func (h *SubscriptionHandler) toSubscriptionResponseWithMaps(sub *model.Subscrip } resp := map[string]any{ "id": sub.UUID, - "apiId": apiIdForResponse, + "artifactId": artifactIdForResponse, "subscriberId": sub.SubscriberID, "organizationId": h.subscriptionService.ResolveOrgHandle(sub.OrganizationUUID), "status": string(sub.Status), diff --git a/platform-api/resources/openapi.yaml b/platform-api/resources/openapi.yaml index 4ed47a681..a805d0398 100644 --- a/platform-api/resources/openapi.yaml +++ b/platform-api/resources/openapi.yaml @@ -4160,8 +4160,8 @@ paths: post: summary: Create subscription description: | - Creates a subscription for the specified API. - `subscriberId` identifies the unique subscriber for this API, allowing multiple subscribers to create subscriptions for the same API. + Creates a subscription for the specified artifact. + `subscriberId` identifies the unique subscriber for this artifact, allowing multiple subscribers to create subscriptions for the same artifact. operationId: CreateSubscription security: - OAuth2Security: @@ -4200,8 +4200,8 @@ paths: get: summary: List subscriptions description: | - Returns subscriptions filtered by API and/or application. - Optional query parameters apiId, subscriberId, applicationId and status filter the list. + Returns subscriptions filtered by artifact and/or application. + Optional query parameters artifactId, subscriberId, applicationId and status filter the list. Supports pagination via limit and offset. operationId: ListSubscriptions security: @@ -4211,10 +4211,10 @@ paths: tags: - Subscriptions parameters: - - name: apiId + - name: artifactId in: query required: false - description: Filter by API ID (UUID or handle) + description: Filter by artifact ID (UUID or handle) schema: type: string - name: subscriberId @@ -6398,18 +6398,18 @@ components: CreateSubscriptionRequest: type: object required: - - apiId + - artifactId - kind - subscriberId properties: - apiId: + artifactId: type: string description: Handle (ID) of the artifact to subscribe to. Resolved against the table for the given kind. example: "my-rest-api" kind: type: string enum: [RestApi, LlmProvider, LlmProxy, Mcp] - description: Type of the artifact identified by apiId. Determines which artifact table apiId is resolved against. + description: Type of the artifact identified by artifactId. Determines which artifact table artifactId is resolved against. example: "RestApi" subscriberId: type: string @@ -6437,7 +6437,7 @@ components: type: string format: uuid description: Subscription ID - apiId: + artifactId: type: string description: Handle (ID) of the subscribed artifact example: "my-rest-api" From 96a33d0de15e83e7140fd415257c32dbec943d56 Mon Sep 17 00:00:00 2001 From: Piumal Rathnayake Date: Wed, 15 Jul 2026 22:31:35 +0530 Subject: [PATCH 2/2] Fix tests --- tests/integration-e2e/steps_devportal_lifecycle_test.go | 2 +- tests/integration-e2e/steps_secured_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration-e2e/steps_devportal_lifecycle_test.go b/tests/integration-e2e/steps_devportal_lifecycle_test.go index 9237e87e5..36d657555 100644 --- a/tests/integration-e2e/steps_devportal_lifecycle_test.go +++ b/tests/integration-e2e/steps_devportal_lifecycle_test.go @@ -157,7 +157,7 @@ func (w *world) verifySubPlan() error { deadline := time.Now().Add(pollTimeout) var last string for time.Now().Before(deadline) { - st, body, err := apiCall(http.MethodGet, "/subscriptions?apiId="+w.apiID, suite.token, nil) + st, body, err := apiCall(http.MethodGet, "/subscriptions?artifactId="+w.apiID, suite.token, nil) if err == nil && st == http.StatusOK { var env struct { List []map[string]any `json:"list"` diff --git a/tests/integration-e2e/steps_secured_test.go b/tests/integration-e2e/steps_secured_test.go index f133c180b..fcb8475a6 100644 --- a/tests/integration-e2e/steps_secured_test.go +++ b/tests/integration-e2e/steps_secured_test.go @@ -194,7 +194,7 @@ func createApplication(name, projectID string) (string, error) { func createSubscription(apiID, appID, planID string) (string, error) { st, body, err := apiCall(http.MethodPost, "/subscriptions", suite.token, map[string]any{ - "apiId": apiID, + "artifactId": apiID, "kind": "RestApi", "subscriberId": "e2e-subscriber", "applicationId": appID,