Create ApiProducts
Bundle your APIs into versioned ApiProducts and expose them in the portal catalog.
An ApiProduct is a logical API offering that groups one or more versions of an API. Each version references an HTTPRoute that serves that version’s traffic. The portal controller automatically links the HTTPRoute’s backend services to their ApiDocs and stitches the schemas together into a single generated ApiDoc per version so that they can be rendered in the portal frontend.
You do not reference ApiDocs directly in an ApiProduct. The controller discovers them implicitly through the HTTPRoute’s backend services as shown in this diagram.
flowchart LR
APV[ApiProduct Version] -->|targetRefs| HR[HTTPRoute]
HR -->|backendRefs| Svc[Service]
AD[ApiDoc] -->|servedBy| Svc
APV -.->|controller generates| SAD[Stitched ApiDoc]
- An ApiProduct version references one or more HTTPRoutes via the
targetRefsfield. - The portal controller examines each HTTPRoute’s
backendRefsto find the backend services. - The portal controller finds the ApiDocs that are served by these services by using the
servedByfield. - The portal controller stitches the matching schemas together into a single generated ApiDoc per version.
Before you begin
- Follow the Get started guide to install Solo Enterprise for kgateway.
- Set up a portal.
- Create an ApiDoc for your service. The example in this guide uses the petstore app.
Create an ApiProduct
Create an ApiProduct and define one or more versions of your API. Each version references the HTTPRoute that serves that version of the API.
Single API version
Create an ApiProduct with a single version of the petstore API. The ApiProduct references the petstore HTTPRoute that you created before you began.
kubectl apply -f- <<EOF
apiVersion: portal.solo.io/v1alpha1
kind: ApiProduct
metadata:
name: petstore-api
namespace: default
spec:
id: petstore
displayName: "Petstore API"
customMetadata:
category: "Pet Management"
versions:
- name: v1
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: petstore-route
openApiMetadata:
title: "Petstore API"
description: "Manage your pets"
EOF| Setting | Description |
|---|---|
id | A URL-safe unique identifier for the ApiProduct (1–128 characters). This ID is used to construct the API URL in the portal API catalog. |
displayName | Human-readable name for that API that is displayed in the portal UI. |
customMetadata | Optional arbitrary key-value pairs that are surfaced in the portal UI. You can have a maximum of 16 entries. |
versions[].name | The version identifier, such as v1 or v2. |
versions[].targetRefs | Reference the HTTPRoutes that serve this version. |
versions[].openApiMetadata | Optional metadata that are merged into the stitched OpenAPI schema for this version. This information is displayed in the portal UI when you select this API version. |
Multiple API versions
An ApiProduct can expose multiple API versions simultaneously. Each version references its own HTTPRoute independently. The portal UI displays a version selector for products with multiple versions.
Create a second HTTPRoute for the
v2version of the API. Make sure to use a unique matcher so that requests can be correctly routed to this version. The matcher must be different from the matcher that you use for thev1version of the API.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: petstore-v2-route namespace: default spec: parentRefs: - name: portal-gateway namespace: default hostnames: - "api.example.com" rules: - matches: - path: type: PathPrefix value: /petstore/v2 filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: / backendRefs: - name: petstore port: 8080 EOFCreate the ApiProduct and include both versions of your API.
kubectl apply -f- <<EOF apiVersion: portal.solo.io/v1alpha1 kind: ApiProduct metadata: name: petstore-api namespace: default spec: id: petstore displayName: "Petstore API" versions: - name: v1 targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: petstore-route openApiMetadata: title: "Petstore API v1" description: "Manage your pets" - name: v2 targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: petstore-v2-route openApiMetadata: title: "Petstore API v2" description: "Manage your pets (v2)" EOFVerify that a stichted ApiDoc is generated for each version of the API. Each version gets its own generated ApiDoc named
<apiproduct-name>-<version-name>.kubectl get apidocs -AExample output:
NAMESPACE NAME SOURCE READY AGE default petstore-api-v1 Stitched True 1m default petstore-api-v2 Stitched True 1m default petstore-url-apidoc Url True 1m
Add the ApiProduct to the portal
Update the Portal resource to include the ApiProduct in its catalog. The portal controller regenerates the PortalConfig after you update the Portal.
Reference an ApiProduct in the same namespace as the Portal.
kubectl apply -f- <<EOF
apiVersion: portal.solo.io/v1alpha1
kind: Portal
metadata:
name: my-portal
namespace: default
spec:
parametersRef:
name: portal-params
visibility:
public: true
apiProductRefs:
- name: petstore-api
- name: httpbin-api
EOFReference an ApiProduct in a different namespace by specifying the namespace field. Cross-namespace references require a ReferenceGrant in the target namespace to authorize the reference.
Create a ReferenceGrant in the namespace where the ApiProduct lives (
other-namespace) to allow the Portal in thedefaultnamespace to reference it.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: portal-apiproduct-grant namespace: other-namespace spec: from: - group: portal.solo.io kind: Portal namespace: default to: - group: portal.solo.io kind: ApiProduct EOFCreate the Portal and reference the ApiProduct in
other-namespace.kubectl apply -f- <<EOF apiVersion: portal.solo.io/v1alpha1 kind: Portal metadata: name: my-portal namespace: default spec: parametersRef: name: portal-params visibility: public: true apiProductRefs: - name: petstore-api namespace: other-namespace - name: httpbin-api EOF
Include all ApiProducts in a namespace by using a wildcard for the name field.
kubectl apply -f- <<EOF
apiVersion: portal.solo.io/v1alpha1
kind: Portal
metadata:
name: my-portal
namespace: default
spec:
parametersRef:
name: portal-params
visibility:
public: true
apiProductRefs:
- name: "*"
namespace: default
EOFVerify your ApiProduct
List the ApiProducts and ApiDocs in your namespace. For each ApiProduct version, the controller generates a stitched ApiDoc that is named
<apiproduct-name>-<version-name>.kubectl get apiproduct,apidoc -n defaultExample output:
NAME ID DISPLAY NAME READY apiproduct.portal.solo.io/petstore-api petstore Petstore API True NAME SOURCE READY AGE apidoc.portal.solo.io/petstore-api-v1 Stitched True 24m apidoc.portal.solo.io/petstore-api-v2 Stitched True 7m21s apidoc.portal.solo.io/petstore-url-apidoc Url True 22hIf an ApiProduct does not show
Ready=True, describe the resource to see the error details.kubectl describe apiproduct petstore-api -n defaultVerify that the PortalConfig was updated with the ApiProduct. The
spec.apisfield must contain an entry for each ApiProduct version and a reference to the generated stitched ApiDoc resource.kubectl get portalconfig my-portal -n default -o yamlExample output:
... spec: apis: - apiDocRef: name: petstore-api-v1 namespace: default apiProductDisplayName: Petstore API apiProductId: petstore apiVersion: v1 description: Manage your pets title: Petstore API v1 - apiDocRef: name: petstore-api-v2 namespace: default apiProductDisplayName: Petstore API apiProductId: petstore apiVersion: v2 description: Manage your pets (v2) title: Petstore API v2 - apiDocRef: name: httpbin-api-v1 namespace: default apiProductCustomMetadata: category: Utilities apiProductDisplayName: HTTPBin API apiProductId: httpbin apiVersion: v1 description: A simple HTTP request/response service for testing title: HTTPBin API portalMetadata: name: my-portal