Bundle your APIs into API products

You deployed your OpenAPI apps and created ApiDocs so that Gloo can stitch together the APIs into a servable schema. Now, you want to bundle your APIs together into API products.

About API products

API products might represent an entire product with many APIs, such as a pet store, or a large feature within the product that you want to treat separately, such as a checkout cart. To bundle your APIs into an API product, you use a Gloo RouteTable custom resource.

By using a Gloo route table, you can automatically add apps via Kubernetes labels or specify them at more fine-grained levels. You also get more advanced networking control, such as matching, redirect, rewrite, direct response, and forwarding actions. This way, you can set up complex rules for how your API products behave under different circumstances.

Route tables allow you to choose the API product strategy that's right for your developer portal.

The API products in a route table are exposed through a Gloo virtual gateway resource. Your end users can access these API products securely via the ingress gateway by logging into the developer portal frontend that you deploy later.

With the examples in this guide, you can build a flexible API product setup as shown in the following diagram.

API product routing overview

  1. The APIs are the apps that you previously deployed, and represent the destinations that you can route requests to. Each app has a corresponding Gloo ApiDoc that defines the OpenAPI spec.
  2. Two route tables represent the API products that you want to create. These route tables send requests to the backing destinations in the previous step.
    • The Tracks route table represents a single microservice, the tracks API.
    • The Petstore route table represents three microservices, the pets, store, and users APIs. Gloo can stitch together these services into a single schema to bundle and share these APIs as a single API product in the developer portal.
  3. Another route table is used for the host, api.example.com, that you want to use for all your API products. This route table delegates to the Tracks and Petstore route tables to include both of those API products.
  4. The virtual gateway routes ingress requests from your end users along the api.example.com host to the matching route table. In turn, the api.example.com route table forwards requests to the matching route tables for APIs in each API product.

Before you begin

  1. Optional: Review the About API products section to learn more about API products and the example setup that you can create by following this guide's steps.
  2. Create your APIs, including the Gloo ApiDocs that describe the stitched schema.

Step 1: Bundle your APIs into an API product

Create a route table for the apps that you previously deployed. This way, Gloo knows which backing APIs to use to serve information for requests along particular paths.

The following steps create two route tables.

  1. Decide on the information for your Tracks API product to display in the end-user facing API documentation in your developer portal. At a minimum, each route table for a portal must include an apiProductId and an apiVersion. You can also include other portal metadata, as shown in the following example. For more multiple versions of your APIs, see Version your APIs. For more information about each setting, see the API docs.

      portalMetadata:
        apiProductId: "tracks"
        apiProductDisplayName: "Catstronauts Course Tracks"
        apiVersion: "v1"
        title: "Catstronauts REST API"
        description: "REST API for Catstronauts to retrieve data for tracks, authors and modules."
        termsOfService: "You must authenticate to use this API! And other Terms of Service."
        contact: "support@example.com"
        license: "License info, such as MIT"
        lifecycle: "Supported"
        customMetadata:
          compatibility: "None"
    
  2. Create a route table to represent an API Product for a single API, such as your tracks app.

    kubectl apply -f - << EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: tracks-rt
      namespace: gloo-mesh-gateways
      labels:
         portal: dev-portal
         api: tracks
    spec:
      http:
      - name: tracks-api
        labels:
          usagePlans: dev-portal
        matchers:
        - uri:
            prefix: /
        forwardTo:
          pathRewrite: /
          destinations:
          - ref:
              name: tracks-rest-api
              namespace: tracks
            port:
              number: 5000
      portalMetadata:
        apiProductId: "tracks"
        apiProductDisplayName: "Catstronauts Course Tracks"
        apiVersion: "v1"
        title: "Catstronauts REST API"
        description: "REST API for Catstronauts to retrieve data for tracks, authors and modules."
        termsOfService: "You must authenticate to use this API! And other Terms of Service."
        contact: "support@example.com"
        license: "License info, such as MIT"
        lifecycle: "Supported"
        customMetadata:
          compatibility: "None"
    EOF
    

    Review the following table to understand this configuration. For more information, see the API docs.

    Setting Description
    Namespace Create the route table in the same namespace, or import it into the same Gloo workspace as the ingress gateway. In this example, the route table is in the same namespace as the ingress gateway, gloo-mesh-gateways.
    Labels Include labels to help select this route table with other portal resources later. This example has two labels. The portal: dev-portal label can be used to associate this route table as part of the dev-portal collection of Gloo resources, while the api: tracks label can be used to associate this route table more specifically with the Tracks API.
    HTTP name and labels Name your route and add a label that you can use to apply the policies of your usage plan to the route later. In this example, the tracks-api route has a usagePlans: dev-portal label.
    HTTP matchers and forwardTo for the route For each app that you want to expose APIs for, define the route matchers that you want the APIs to be available on. This example defines the / route for the tracks-rest-api. Then, these routes are available on the matching host, such as api.example.com/.
    Portal metadata A set of key-value pairs that describe your API, which you put together in the previous step. Later, your developer portal displays this information in the end-user facing API documentation.
  3. Decide on the information for your Pet Store API product, which is a collection of serveral microservices that you previously deployed. Later, your developer portal displays this information in the end-user facing API documentation. At a minimum, each route table for a portal must include an apiProductId and an apiVersion. You can also include other portal metadata, as shown in the following example. For more information, see the API docs.

      portalMetadata:
        apiProductId: "petstore"
        apiProductDisplayName: "Pet Store"
        apiVersion: "v1"
        title: "Pet Store REST API"
        description: "Totally awesome API for all things pets!"
        termsOfService: "You must authenticate to use this API! And other Terms of Service."
        contact: "support@example.com"
        license: "License info, such as MIT"
        lifecycle: "Supported"
        customMetadata:
          compatibility: "None"
    
  4. Create a route table that represents the Pet Store API product for your pets, users, and store API microservices.

    kubectl apply -f - << EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: petstore-rt
      namespace: gloo-mesh-gateways
      labels:
         portal: dev-portal
         api: petstore
    spec:
      http:
      - name: pets-api
        labels:
          usagePlans: dev-portal
        matchers:
        - uri:
            prefix: /pet
        forwardTo:
          destinations:
          - ref:
              name: pets-rest-api
              namespace: pets
            port:
              number: 5000
      - name: users-api
        labels:
          usagePlans: dev-portal
        matchers:
        - uri:
            prefix: /user
        forwardTo:
          destinations:
          - ref:
              name: users-rest-api
              namespace: users
            port:
              number: 5000
      - name: store-api
        labels:
          usagePlans: dev-portal       
        matchers:
        - uri:
            prefix: /store
        forwardTo:
          destinations:
          - ref:
              name: store-rest-api
              namespace: store
            port:
              number: 5000
      portalMetadata:
        apiProductId: "petstore"
        apiProductDisplayName: "Pet Store"
        apiVersion: "v1"
        title: "Pet Store REST API"
        description: "Totally awesome API for all things pets!"
        termsOfService: "You must authenticate to use this API! And other Terms of Service."
        contact: "support@example.com"
        license: "License info, such as MIT"
        lifecycle: "Supported"
        customMetadata:
          compatibility: "None"
    EOF
    

    Review the following table to understand this configuration. For more information, see the description from the previous step and the API docs.

    Setting Description
    HTTP name and labels Name your route and add a label that you can use to apply the policies of your usage plan to the route later. In this example, each route has a usagePlans: dev-portal label.
    HTTP matchers and forwardTo for the route For each app that you want to expose APIs for, define the route matchers that you want the APIs to be available on. This example defines three routes: /pet, /user, and /store. These routes correspond to three APIs that you previously deployed, which Gloo can then stitch together into a single schema to build the Petstore API product. Then, these routes are available on the matching host, such as api.example.com/pet, api.example.com/users, or api.example.com/store.
    Portal metadata A set of key-value pairs that describe your API, which you put together in the previous step. Later, your developer portal displays this information in the end-user facing API documentation.
  5. To configure the domain that you want your API products exposed on, continue to the next step.

Step 2: Create a domain-level route table for multiple API products

For many use cases, your developer portal exposes several API products. To support this setup, you can create one overarching route table for the domain of your developer portal. Then, you can delegate matching routes along certain API paths to other route tables that represent that API product.

This way, you have one main route table for the domain that you can use to expose all of the API products that it includes, such as when you create a usage plan. You can easily add more API products by delegating to more route tables. You also still keep the flexibility to apply usage plans to the particular API product's route tables within the overarching domain's route table, for more granular control.

  1. Create individual route tables for each API product that you want to expose.

  2. Create a route table for the domain that you want your API products to be exposed on. This route table delegates the routing rules for matching HTTP routes to the route tables that you previously created. Note that the following example does not set any portal metadata, because that information is set per API product in the delegated route tables.

    If you only want a single route table for one API product, just add the hosts and virtual gateway fields from the following spec example to each API product's route table.

    kubectl apply -f - << EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: api-example-com-rt
      namespace: gloo-mesh-gateways
    spec:
      hosts:
      - api.example.com
      virtualGateways:
      - name: istio-ingressgateway
        namespace: gloo-mesh-gateways
      http:
      - matchers:
        - uri:
            prefix: /trackapi
        delegate:
          routeTables:
            - labels:
                api: tracks
      - matchers:
        - uri:
            prefix: /petstore
        delegate:
          routeTables:
            - labels:
                api: petstore
    EOF
    

    Review the following table to understand this configuration. For more information, see the API docs.

    Setting Description
    Namespace Create the route table in the same namespace or import it into the same Gloo workspace as the ingress gateway. In this example, the route table is in the same namespace as the ingress gateway, gloo-mesh-gateways.
    Hosts Add the host domains that you want the API products to be exposed on, such as api.example.com.
    Virtual gateway Select the ingress gateway with the host that you want to use to expose your apps’ APIs. In this example, the default ingress gateway is selected.
    HTTP matchers and delegations For each API product that you want to expose on the host domain, set up matchers and delegated route tables. In this example, requests that match /trackapi are delegated to the Tracks route table. Requests that match /petstore are delegated to the Petstore route table.
  3. To create the virtual gateway for the domain that you want your API products to be exposed on, continue to the next step.

Step 3: Create the virtual gateway for your domain

To expose your API products, configure the ingress gateway to listen on a host and forward requests to the route tables.

The following example configures a simple HTTP gateway. For more examples such as HTTPS/TLS, see Configure gateway listeners.

  1. Create individual route tables for each API product that you want to expose.

  2. Optional: Create a domain-level route table if you want to expose several API products on the same domain.

  3. Create a virtual gateway for the host domain that you want to expose your API products on.

    kubectl apply -f - << EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: VirtualGateway
    metadata:
      name: istio-ingressgateway
      namespace: gloo-mesh-gateways
    spec:
      listeners:
        - port:
            number: 80
          http: {}
          allowedRouteTables:
            - host: api.example.com
      workloads:
      - selector:
          labels:
            istio: ingressgateway
          cluster: $CLUSTER_NAME
    EOF
    

    Review the following table to understand this configuration. For more information, see the API docs.

    Setting Description
    Listener's allowed route tables Add the host domain that matches the route table for the API products that you want to expose. In this example, the api.example.com matches the host in the domain-level route table that you created to expose together your two API products, Tracks and Petstore.
  4. To verify your setup, continue to the next step.

Step 4: Verify your setup

You can use the Gloo UI and the terminal to verify your API product routing setup.

Gloo UI

Review the stitched API schemas for your API products in the Gloo UI.

  1. Launch the Gloo UI.
    meshctl dashboard
    
  2. From the menu, navigate to the APIs > API Registry page and verify that you have two API products for both of the route tables that you created, petstore-rt and tracks-rt. Gloo UI view of API products
  3. Click one of the API products and verify that you can see the following information:
    • The API Schema that describes your app's REST APIs. You can also click View OpenAPI to see the stitched schema of the API product in JSON format.
    • The Applied to Destinations shows the backing destinations of all of the apps that are included in the API product.
    • Note that the Portals are not shown yet, because you have not created the Portal resource. Gloo UI detailed view of API products

Terminal

Verify that you can access your APIs through the ingress gateway on the host domain that you configured.

  1. Get the external address of the ingress gateway. If you deployed your ingress gateway in a different namespace or with a different version, update the command.

    export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo $INGRESS_GW_IP
    
    export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    echo $INGRESS_GW_IP
    

    Note: Depending on your environment, you might see <pending> instead of an external IP address. For example, if you are testing locally in kind or minikube, or if you have insufficent permissions in your cloud platform, you can instead port-forward the service port of the ingress gateway:

    kubectl -n gloo-mesh-gateways port-forward deploy/istio-ingressgateway-1-20 8081
    
  2. In your terminal, send a curl request to both of the API products that you set up. Note that the routes are not yet secured. You secure the routes with rate limiting and external auth policies later as part of your portal's usage plan.

    • api.example.com is the host that you set in both the domain-level route table and the virtual gateway.
    • /trackapi is the prefix that you set in both the domain-level route table to delegate requests to the tracks-rt route table.
    • /tracks is an endpoint from the tracks API in the tracks-rt route table.
    curl -v --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/trackapi/tracks
    

    Example output:

    < HTTP/1.1 200 OK
    ...
    [
      {
        "id": "c_0",
        "thumbnail": "https://res.cloudinary.com/dety84pbu/image/upload/v1598465568/nebula_cat_djkt9r.jpg",
        "topic": "Cat-stronomy",
        "authorId": "cat-1",
        "title": "Cat-stronomy, an introduction",
        "description": "Curious to learn what Cat-stronomy is all about? Explore the planetary and celestial alignments and how they have affected our space missions.",
        "numberOfViews": 163,
        "createdAt": "2018-09-10T07:13:53.020Z",
        "length": 2377,
        "modulesCount": 10,
        "modules": [
          "l_0",
          "l_1",
          "l_2",
          "l_3",
          "l_4",
          "l_5",
          "l_6",
          "l_7",
          "l_8",
          "l_9"
        ]
      },
    ...
    
    • api.example.com is the host that you set in both the domain-level route table and the virtual gateway.
    • /petstore is the prefix that you set in both the domain-level route table to delegate requests to the petstore-rt route table.
    • /pet, /user, and /order are endpoints from the stitched API schema of the petstore-rt route table. Note that, even though these APIs are served by different backing destinations, they are all available under the same /petstore prefix for the single route table that you set up for this Petstore API product.
    curl -v --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/petstore/pet
    curl -v --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/petstore/user
    curl -v --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/petstore/store/order
    

    Example output:

    < HTTP/1.1 200 OK
    ...
    [
      {
        "id": 1,
        "name": "Barky",
        "photoUrls": [
          "image1.jpg"
        ],
    ...
    

Next steps

With API products in place, you are one step closer to sharing your APIs with the world.

Next, you can work with your Portal Admin to protect your APIs by creating usage plans.

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