Create a portal
Create the backend and frontend of your developer portal.
Previously, you bundled your apps into API products. Now, you configure the backend and frontend of your developer portal to serve the API products 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
Create a Portal custom resource.
kubectl apply -f- <<EOF apiVersion: apimanagement.gloo.solo.io/v2 kind: Portal metadata: name: developer-portal namespace: gloo-mesh 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
Review the following table to understand this configuration. For more information, see the API reference docs.
Field Description metadata Note that the Portal is created in the same namespace as the portal server, gloo-mesh
.visibility Decide 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 totrue
so that any user can view the ApiProductsdomains Set the host domain that you want to expose the backend portal on. Note that this is not the same as the URL that your end users access the frontend portal on. The example sets developer.example.com
.portalBackendSelectors Select the backing portal server that you deployed when you installed Gloo Mesh Gateway. usagePlans Configure the usage plans that you want to make available for APIs that are exposed through this developer portal. In the example, you create three usage plans: bronze, silver, and gold. These values match the values that you use in the setDescriptors
of the RateLimitServerConfig, to rate limit requests per usage plan.apis Select the ApiProducts to include in the portal. The example uses the label selector expose-portal: "true"
, which you set in the object metadata of the ApiProducts that you previously created.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-mesh
Example output:
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-cluster-1-portal namespace: gloo-mesh 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 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 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 public: true kind: List metadata: resourceVersion: "" selfLink: ""
Step 2: Create a route to the portal
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 Mesh Gateway 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 - host: portal.example.com http: {} port: number: 80 workloads: - selector: cluster: $CLUSTER_NAME labels: istio: ingressgateway EOF
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 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
For local development and testing, apply a CORS policy. This way, you can access the portal frontend that you set up later from your localhost.
kubectl apply -f -<<EOF apiVersion: security.policy.gloo.solo.io/v2 kind: CORSPolicy metadata: name: dev-portal-cors namespace: gloo-mesh-gateways spec: applyToRoutes: - route: labels: route: portal-api config: allowCredentials: true allowHeaders: - "Content-Type" - "api-key" - "id_token" - "Authorization" - "Access-Control-Allow-Origin" allowMethods: - GET - POST - DELETE - PUT - OPTIONS allowOrigins: - prefix: http://localhost - prefix: http://127.0.0.1 - prefix: https://developer.example.com - prefix: http://portal.example.com EOF
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.
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
Open the Gloo UI. The Gloo UI is served from the
gloo-mesh-ui
service on port 8090. You can connect by using themeshctl
orkubectl
CLIs.- meshctl: For more information, see the CLI documentation.
meshctl dashboard
- kubectl:
- Port-forward the
gloo-mesh-ui
service on 8090.kubectl port-forward -n gloo-mesh svc/gloo-mesh-ui 8090:8090
- Open your browser and connect to http://localhost:8090.
- Port-forward the
- meshctl: For more information, see the CLI documentation.
From the menu, navigate to the APIs > Portals page.
- Click your portal and review the Published APIs and Usage Plans of the portal.
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.
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 thedeveloper.example.com
route that you previously created for the backend portal.kubectl apply -n gloo-mesh -f- <<EOF apiVersion: v1 kind: ServiceAccount metadata: name: portal-frontend namespace: gloo-mesh --- apiVersion: v1 kind: Service metadata: name: portal-frontend namespace: gloo-mesh 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-mesh 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/v1 # The URL that the backend Portal is exposed on via a RouteTable. EOF
Expose the frontend app securely through the ingress gateway. The following example uses the host
portal.example.com
. It refers to the virtual gateway that you created when you configured the developer portal. For more examples such as HTTPS/TLS, see Configure gateway listeners.kubectl apply -f- <<EOF apiVersion: networking.gloo.solo.io/v2 kind: RouteTable metadata: name: portal-frontend namespace: gloo-mesh-gateways labels: app: portal-frontend spec: hosts: - "portal.example.com" virtualGateways: - name: istio-ingressgateway-portal namespace: gloo-mesh-gateways http: - name: portal-frontend forwardTo: destinations: - port: number: 4000 ref: name: portal-frontend namespace: gloo-mesh cluster: $CLUSTER_NAME labels: route: portal-api matchers: - uri: prefix: / EOF
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.
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.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
In your browser, open the web UI of the frontend portal app, http://portal.example.com:8080/.
When you open the web UI, you might see the following message:no healthy upstream
. The portal frontend app is probably still in process. View the logs until you see a message that indicates that the portal frontend app is available. The process can take a few minutes. To view the logs, runkubectl logs -n gloo-system deploy/portal-frontend
.open http://portal.example.com:8080/
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.
Click the Pet Store REST API. You can review the OpenAPI spec for each route in the ApiProduct, for
pet
,store
, anduser
. To get a JSON file of the OpenAPI spec from either view, click Download.Click Swagger View to toggle the view from Redocly to Swagger.
Good job! You set up and explored the developer portal.
Next steps
So far, you have a basic portal backend and frontend set up. However, the portal is not secured. Anyone with the link can access the portal. Continue with the following tutorials to add more security to your portal:
- Protect your APIs with external auth and rate limit policies.
- Secure access to the portal by requiring users to log in through an OpenID Connect (OIDC) provider.