Create and expose the portal

Now that you decided on your portal configuration, you can create your developer portal and make it available to your users.

Before you begin

Create and expose the developer portal

In this guide, you create your portal resource and expose the portal backend so that you can interact with your portal by using your terminal.

  1. Create the developer portal. The following portal resource creates a developer portal for the developer.example.com host and includes all API products with the portal: dev-portal label. If you followed the examples in Decide on your portal configuration, the tracks and petstore API products are served by this portal resource.

    kubectl apply -f- <<EOF
    apiVersion: apimanagement.gloo.solo.io/v2
    kind: Portal
    metadata:
      name: developer-portal
      namespace: gloo-mesh-addons
    spec:
      visibility:
        public: true
        privateAPILabels:
          portal-visibility: private
      domains:
        - "developer.example.com"
      portalBackendSelectors:
        - selector:
            labels:
              app: gloo-mesh-portal-server
      usagePlans:
        - name: bronze
          displayName: "Bronze Plan"
          description: "A basic usage plan"
        - name: silver
          description: "A better usage plan"
        - name: gold
          description: "The best usage plan!"
      apis:
        - labels:
            portal: dev-portal 
    EOF
    
  2. Verify that the internal PortalConfig resource is created for your portal. By default, this resource is created in the gloo-mesh-addons namespace.

    kubectl get portalconfigs -n gloo-mesh-addons -o yaml
    

    Example output: Notice that the stitched schema is used, as well as the portal metadata that you set in the route table.

    apiVersion: v1
    items:
    - apiVersion: internal.gloo.solo.io/v2
      kind: PortalConfig
      metadata:
        annotations:
          cluster.solo.io/cluster: cluster-1
        creationTimestamp: "2023-04-06T21:30:41Z"
        generation: 1
        labels:
          context.mesh.gloo.solo.io/cluster: cluster-1-portal
          context.mesh.gloo.solo.io/namespace: gloo-mesh-gateways
          context.mesh.gloo.solo.io/workspace: cluster-1-portal
          gloo.solo.io/parent_cluster: cluster-1-portal
          gloo.solo.io/parent_group: ""
          gloo.solo.io/parent_kind: Namespace
          gloo.solo.io/parent_name: gloo-mesh-gateways
          gloo.solo.io/parent_namespace: ""
          gloo.solo.io/parent_version: v1
          reconciler.mesh.gloo.solo.io/name: translator
        name: developer-portal-gloo-mesh-addons-cluster-1-portal
        namespace: gloo-mesh-addons
        resourceVersion: "1985686"
        uid: 59fe5508-d839-4720-b6ae-59347664e3bb
      spec:
        apis:
        - apiSchema:
            cluster: cluster-1-portal
            name: tracks-rt-stitched-openapi-cluster-1-portal-gloo-mesh-gateways-cluster-1-portal
            namespace: gloo-mesh-addons
          contact: support@example.com
          description: REST API for Catstronauts to retrieve data for tracks, authors
         and modules.
          license: license info
          routeTable:
            cluster: cluster-1-portal
            name: tracks-rt
            namespace: gloo-mesh-gateways
          termsOfService: You must authenticate to use this API! And other Terms of Service.
          title: Catstronauts REST API
        - apiSchema:
            cluster: cluster-1-portal
            name: petstore-rt-stitched-openapi-cluster-1-portal-gloo-mesh-gateways-cluster-1-portal
            namespace: gloo-mesh-addons
          contact: support@example.com
          description: Totally awesome API for all things pets!
          license: license info
          routeTable:
            cluster: cluster-1-portal
            name: petstore-rt
            namespace: gloo-mesh-gateways
          termsOfService: You must authenticate to use this API! And other Terms of Service.
          title: Petstore REST API
        domains:
        - developer.example.com
        portalRef:
          cluster: cluster-1-portal
          name: developer-portal
          namespace: gloo-mesh-addons
        public: true
    kind: List
    metadata:
      resourceVersion: ""
      selfLink: ""
       

  3. Create a virtual gateway that you use to expose the developer portal. The following example selects the default ingress gateway that you deployed during your Gloo Platform installation. For more examples such as HTTPS/TLS, see Configure gateway listeners.

    kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: VirtualGateway
    metadata:
      name: istio-ingressgateway-portal
      namespace: gloo-mesh-gateways
    spec:
      listeners:
        - allowedRouteTables:
            - host: developer.example.com
          http: {}
          port:
            number: 80
      workloads:
        - selector:
            cluster: $CLUSTER_NAME
            labels:
              istio: ingressgateway
    EOF
    
  4. Create a route table for the developer portal. The following route table creates routes for all the portal APIs so that you can interact with your developer portal.

    kubectl apply -f - <<EOF    
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: dev-portal-rt
      namespace: gloo-mesh-gateways
    spec:
      hosts:
      - developer.example.com
      virtualGateways:
      - name: istio-ingressgateway-portal
        namespace: gloo-mesh-gateways
      defaultDestination:
        port:
          number: 8080
        ref:
          name: gloo-mesh-portal-server
          namespace: gloo-mesh-addons
          cluster: $CLUSTER_NAME
      http:
        #
        # Portal server routes that require authentication.
        #
        - forwardTo: {}
          name: authn
          labels:
            oauth: "true" # Use this label to apply an OAuth external auth policy
            route: portal-api
          matchers:
            #
            # /v1/me
            - uri:
                prefix: /v1/me
              method: OPTIONS
            - uri:
                prefix: /v1/me
              method: GET
              headers:
                - name: Authorization
                  value: "Bearer.*"
                  regex: true
            #
            # /v1/apis
            - uri:
                prefix: /v1/apis
              method: GET
              headers:
                - name: Authorization
                  value: "Bearer.*"
                  regex: true
            #
            # /v1/usage-plans
            - uri:
                prefix: /v1/usage-plans
              method: GET
              headers:
                - name: Authorization
                  value: "Bearer.*"
                  regex: true
            #
            # /v1/api-keys
            - uri:
                prefix: /v1/api-keys
              method: GET
              headers:
                - name: Authorization
                  value: "Bearer.*"
                  regex: true
            - uri:
                prefix: /v1/api-keys
              method: POST
              headers:
                - name: Authorization
                  value: "Bearer.*"
                  regex: true
            - uri:
                prefix: /v1/api-keys
              method: DELETE
              headers:
                - name: Authorization
                  value: "Bearer.*"
                  regex: true
        #
        # Portal server routes that are public and do not require authentication.
        #
        - forwardTo: {}
          name: no-auth
          labels:
            route: portal-api
          matchers:
            - uri:
                prefix: /v1/apis
              method: GET
            - uri:
                prefix: /v1/usage-plans
              method: GET
            - uri:
                prefix: /v1/api-keys
              method: GET
            #
            # Allow OPTION requests without authentication.
            #
            - uri:
                prefix: /v1/api-keys
              method: OPTIONS
            - uri:
                prefix: /v1/usage-plans
              method: OPTIONS
            - uri:
                prefix: /v1/apis
              method: OPTIONS
    EOF
    
  5. Send a request to the developer portal to list the APIs that you have access to. Note that because the petstore API is set to private, only the tracks API is returned in your CLI output. To view the private petstore APIs, you must set up authentication and authorization. For more information, see Secure the portal.

    The /me and /api-keys paths are protected even if you set API product visibility to public. These API paths cannot be accessed until a user is authenticated with an OIDC provider. For more information, see Set up external authentication.

    curl -vik --resolve developer.example.com:80:$INGRESS_GW_IP http://developer.example.com:80/v1/apis
    

    Example output:

    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    HTTP/1.1 200 OK
    < content-type: application/json
    content-type: application/json
    < date: Fri, 14 Apr 2023 13:57:02 GMT
    date: Fri, 14 Apr 2023 13:57:02 GMT
    < content-length: 387
    content-length: 387
    < x-envoy-upstream-service-time: 0
    x-envoy-upstream-service-time: 0
    < server: istio-envoy
    server: istio-envoy
    
    < 
    [{"apiProductDisplayName":"Catstronauts Course Tracks","apiProductId":"tracks","apiVersions":[{"apiId":"tracks-v1","apiVersion":"v1","contact":"support@example.com","customMetadata":{"compatibility":"None"},"description":"REST API for Catstronauts to retrieve data for tracks, authors and modules.","license":"License info, such as MIT","lifecycle":"Supported","termsOfService":"You must authenticate to use this API! And other Terms of Service.","title":"Catstronauts REST API","usagePlans":["bronze","gold","silver"]}]},{"apiProductDisplayName":"Pet Store","apiProductId":"petstore","apiVersions":[{"apiId":"petstore-v1","apiVersion":"v1","contact":"support@example.com","customMetadata":{"compatibility":"None"},"description":"Totally awesome API for all things pets!","license":"License info, such as MIT","lifecycle":"Supported","termsOfService":"You must authenticate to use this API! And other Terms of Service.","title":"Pet Store REST API","usagePlans":["bronze","gold","silver"]}]}]
    * Connection #0 to host developer.example.com left intact
    
  6. Launch the Gloo UI.

    meshctl dashboard
    
  7. From the menu, navigate to the APIs > Portals page.

    Gloo UI view of portals

  8. Click your portal and review the Published APIs and Usage Plans of the portal.

    Gloo UI detailed view of portals

Next steps

You can continue to use your portal in several ways:

When you are done with trying out Portal, you can clean up all of the resources that you created.