Previously, you bundled your apps into ApiProducts. Now, you configure the backend and frontend of your developer portal to serve the ApiProducts to your end users.

Before you begin

Complete the API product tutorial.

Create the backend portal

Create a Portal that configures the host domain on which you want to expose your ApiProducts to end users.

Step 1: Create the portal

  1. Create a Portal custom resource. You create the Portal in the same namespace as the ApiProducts. This way, you do not need to create a Kubernetes ReferenceGrant to let the Portal refer to the ApiProducts.

      kubectl apply -n gloo-system -f- <<EOF
    apiVersion: portal.gloo.solo.io/v1
    kind: Portal
    metadata:
      name: portal-developer
      namespace: gloo-system
    spec:
      visibility:
        public: true
      apiProducts:
      - name: tracks-svc-api-product
        namespace: gloo-system
      - name: petstore-svc-api-product
        namespace: gloo-system
    EOF
      

    Review the following table to understand this configuration.

    FieldDescription
    metadataNote that the Portal is created in the same namespace as the portal server and ApiProducts, gloo-system. If your Portal is in a different namespace, you must create a Kubernetes ReferenceGrant to let the Portal refer to the portal server’s Service and the ApiProducts.
    visibilityDecide whether the ApiProducts in the portal are visible to all users (public APIs) or if the ApiProducts are hidden until the user successfully authenticates (private APIs). The default value is false to set up private APIs. The example sets the value to true so that any user can view the ApiProducts
    apiProductsSelect the ApiProducts to include in the portal.
  2. Check the status of your ApiProducts. Notice that the ApiProducts are now ACCEPTED because you created a portal that selects them.

      kubectl get apiproducts -n gloo-system -o yaml | grep status -A5
      

    Example output:

        status:
        state:
          State:
            approval: ACCEPTED
            message: SUCCESS
            observedGeneration: 2
    --
      status:
        state:
          State:
            approval: ACCEPTED
            message: SUCCESS
            observedGeneration: 1
      
  3. Check the ApiDocs again. Notice that Gloo automatically generated an ApiDoc that includes the stitched schema of all the paths that are exposed by each matcher of the HTTPRoutes for each ApiProduct in the same gloo-system namespace as the Portal. For example, you have one stitched schema for the 3 services that are part of the Petstore ApiProduct.

      kubectl get apidocs -A
      

    Example output:

      NAMESPACE     NAME                                        AGE
    gloo-system   store-route-gloo-system-stitched-openapi    10s
    gloo-system   tracks-route-gloo-system-stitched-openapi   10s
    pets          pets-rest-api-service                       26m
    store         store-rest-api-service                      26m
    tracks        tracks-rest-api-service                     26m
    users         users-rest-api-service                      26m
      
  4. Check that Gloo automatically generated a PortalConfig resource. The PortalConfig is an internal resource that Gloo uses to combine the stitched schema of the ApiDoc, the portal metadata of each ApiProduct, and the other details such as visibility and host domain for your Portal.

      kubectl describe portalconfigs -n gloo-system
      

    Example output:

      Name:         portal-developer-gloo-system
    Namespace:    gloo-system
    Labels:       portal.gloo.solo.io/gc_label=gloo-system
    Annotations:  <none>
    API Version:  internal.gloo.solo.io/v2
    Kind:         PortalConfig
    Spec:
      Apis:
        API Id:                    petstore-v1
        API Product Display Name:  Pet Store
        API Product Id:            petstore
        API Schema:
          Name:       pets-route-gloo-system-stitched-openapi
          Namespace:  gloo-system
        API Version:  v1
        Contact:      support@example.com
        Custom Metadata:
          Compatibility:           None
        Description:               Totally awesome API for all things pets!
        License:                   License info, such as MIT
        Lifecycle:                 Supported
        Terms Of Service:          You must authenticate to use this API! And other Terms of Service.
        Title:                     Pet Store REST API
        API Id:                    tracks-v1
        API Product Display Name:  Catstronauts Course Tracks
        API Product Id:            tracks
        API Schema:
          Name:       tracks-route-gloo-system-stitched-openapi
          Namespace:  gloo-system
        API Version:  v1
        Contact:      support@example.com
        Custom Metadata:
          Compatibility:   None
        Description:       REST API for Catstronauts to retrieve data for tracks, authors and modules.
        License:           License info, such as MIT
        Lifecycle:         Supported
        Terms Of Service:  You must authenticate to use this API! And other Terms of Service.
        Title:             Catstronauts REST API
      Domains:
        developer.example.com
      Portal Ref:
        Name:       portal-developer
        Namespace:  gloo-system
      Public:       true
    Status:
      Common:
        State:
          Approval:  ACCEPTED
          Message:   SUCCESS
      

Step 2: Create a route to the portal

  1. Create an HTTPRoute for the backend portal. The HTTPRoute maps your Kubernetes Gateway with the backend portal server and the host domain that you want your backend portal to be available on. You create the HTTPRoute in the same namespace as the portal server. This way, you do not need to create a Kubernetes ReferenceGrant to let the HTTPRoute refer to the portal server’s Service.

      kubectl apply -n gloo-system -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: portal-backend-route
      namespace: gloo-system
    spec:
      parentRefs:
        - name: http
          namespace: gloo-system
      hostnames:
        - developer.example.com
      rules:
        - backendRefs:
            - name: gateway-portal-web-server
              namespace: gloo-system
              port: 8080   
    EOF
      
  2. Confirm that the route references are resolved.

      kubectl get httproutes -n gloo-system portal-backend-route -o yaml
      

    Example output:

      [...]
        - lastTransitionTime: "2024-04-17T18:54:53Z"
          message: ""
          observedGeneration: 2
          reason: ResolvedRefs
          status: "True"
          type: ResolvedRefs   
      

Good job! You set up the backend of your developer portal. The backend means that your ApiProducts are exposed on a backend-facing host, developer.example.com, that your internal services use to route and protect requests to the backing API services.

Next, you can set up a frontend portal.

Create the frontend portal

The frontend portal is the web user interface (UI) application that your end users access. In the portal, your end users can discover and authenticate to use your ApiProducts.

Gloo provides a sample React app that you can use as a starting point to develop your own frontend application. This frontend app displays the information that your Portal resource pulls together: the API products and usage plans that you want to expose, along with additional metadata. Because this information is controlled by the Portal resource, you don’t have to update the frontend app as often after the initial setup.

  1. Deploy the dev-portal-starter sample React app. For more information, see the GitHub project. Notice that the portal server URL environment variable is set with the developer.example.com route that you previously created for the backend portal.

      kubectl apply -n gloo-system -f- <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: portal-frontend
      namespace: gloo-system
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: portal-frontend
      namespace: gloo-system
      labels:
        app: portal-frontend
        service: portal-frontend
    spec:
      ports:
        - name: http
          port: 4000
          targetPort: 4000
      selector:
        app: portal-frontend
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: portal-frontend
      namespace: gloo-system
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: portal-frontend
      template:
        metadata:
          labels:
            app: portal-frontend
        spec:
          serviceAccountName: portal-frontend
          containers:
            - image: gcr.io/solo-public/docs/portal-frontend:latest
              imagePullPolicy: Always
              name: portal-frontend
              args: ["--host", "0.0.0.0"]
              ports:
                - containerPort: 4000
              env:
                - name: VITE_PORTAL_SERVER_URL
                  value: http://developer.example.com:8080/v1 # The URL that the backend Portal is exposed on via an HTTPRoute.
    EOF
      
  2. Verify that the frontend app is running.

      kubectl get all -n gloo-system -l app=portal-frontend
      
  3. Create a RouteOption for a CORS filter. Notice that the RouteOption is in the same namespace as the HTTPRoute for the backend portal server. This way, the frontend portal app can communicate with the backend portal server. The CORS filter allows origin from your local host for development purposes along with the URL that you want the frontend portal to be available on, portal.example.com.

      kubectl apply -n gloo-system -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: RouteOption
    metadata:
      name: portal-cors
      namespace: gloo-system
    spec:
      options:
        cors:
          allowOrigin:
            - http://localhost:4000
            - http://127.0.0.1:4000
            - http://portal.example.com
            - http://portal.example.com:8080
          allowHeaders:
            - "Content-Type"
            - "Authorization"
            - "Access-Control-Allow-Origin"
          allowMethods:
            - GET
            - POST
            - PUT
            - DELETE
            - OPTIONS
          allowCredentials: true   
    EOF
      
  4. Update the HTTPRoute of the backend portal server to apply the RouteOption with the CORS filter.

      kubectl apply -n gloo-system -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: portal-backend-route
      namespace: gloo-system
    spec:
      parentRefs:
        - name: http
          namespace: gloo-system
      hostnames:
        - developer.example.com
      rules:
        - backendRefs:
            - name: gateway-portal-web-server
              namespace: gloo-system
              port: 8080 
          filters:
            - type: ExtensionRef
              extensionRef:
                group: gateway.solo.io
                kind: RouteOption
                name: portal-cors           
    EOF
      
  5. Create an HTTPRoute for the frontend portal app. The route matches the same route that the CORS filter allows originating traffic from, portal.example.com. Your end users can access the frontend portal app on this route. You create the HTTPRoute in the same namespace as the frontend portal app. This way, you do not need to create a Kubernetes ReferenceGrant to let the HTTPRoute refer to the frontend portal app’s Service.

      kubectl apply -n gloo-system -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: portal-frontend-route
      namespace: gloo-system
    spec:
      parentRefs:
        - name: http
          namespace: gloo-system
      hostnames:
        - portal.example.com
      rules:
        - backendRefs:
            - name: portal-frontend
              namespace: gloo-system
              port: 4000
    EOF
      
  6. Verify that the frontend route is created. In the status section, check for Accepted and ResolvedRefs in the reason output.

      kubectl get httproute portal-frontend-route -n gloo-system -o yaml | grep "status" -A15
      

You are almost there! You have all the pieces for a basic developer portal set up. Now, you can check out the portal as an end user.

Explore the portal

Explore how your end users can use the developer portal to discover, access, and use your API products. Because you set the portal visibility to public and did not enforce authentication, you can review all the pages that are available in the web UI.

  1. To have the routing for the frontend portal work on your local machine, update your /etc/hosts to map the IP address of the Kubernetes Gateway to the routes that you created for your APIs, portal backend, and portal frontend. If you are using an actual domain that you own to serve the frontend app, you can skip this step.

      sudo nano /etc/hosts
      

    Replace 18.xxx.xxx.xx with the value of the IP address of your gateway.

    • For gateways with an IP address such as in GCP, get the EXTERNAL-IP of the service by running kubectl get svc -n gloo-system gloo-proxy-http.
    • For gateways that use a load balancer host address such as in AWS, get the EXTERNAL-IP of the service by running kubectl get svc -n gloo-system gloo-proxy-http. Then, get the backing IP address of the load balancer by running dig <loadbalancer-external-IP-host-address>.
      18.xxx.xxx.xx portal.example.com
    18.xxx.xxx.xx developer.example.com
    18.xxx.xxx.xx api.petstore.com
    18.xxx.xxx.xx api.tracks.com
      
  2. In your browser, open the web UI of the frontend portal app, http://portal.example.com:8080/.

      open http://portal.example.com:8080/
      
    Figure: Welcome page of the developer portal.
    Figure: Welcome page of the developer portal.
  3. From the menu bar, click the APIs tab. You find the two ApiProducts that you created in this tutorial. Note that the portal metadata that you configured is shown for the description, version, tags, and other information.

    Figure: API products in the developer portal.
    Figure: API products in the developer portal.
  4. Click the Pet Store REST API. You can review the OpenAPI spec for each route in the ApiProduct, for pet, store, and user. To get a JSON file of the OpenAPI spec from either view, click Download.

    Figure: Redocly view of the OpenAPI spec for the Petstore ApiProduct.
    Figure: Redocly view of the OpenAPI spec for the Petstore ApiProduct.
  5. Click Swagger View to toggle the view from Redocly to Swagger.

    Figure: Swagger view of the OpenAPI spec for the Petstore ApiProduct.
    Figure: Swagger view of the OpenAPI spec for the Petstore ApiProduct.

Good job! You set up and explored the developer portal.