Create an API Product

The first part of the guide demonstrates publishing a simple API as an API Product to which HTTP requests can be routed.

In this guide, we’ll:

  1. Create an API Document from an OpenAPI Schema.
  2. Create an API Product from our API Document.
  3. Create an Environment to expose our API Product
  4. Connect to our API through the Istio or Gloo Edge.

You can find more information about terms like API Document and API Product in our Concepts section of the docs.


For this guide, we’ll need the following:

Install API Backend

In this guide we’ll be using the OpenAPI Example Pet Store as the backend for our API Product.

To install the Pet Store to Kubernetes:

kubectl apply -n default -f \
kubectl -n default rollout status deployment petstore

Then verify that the installation completed successfully:

deployment "petstore" successfully rolled out

Create an API Document

The next step in our process is to create an API Document based on the OpenAPI Schema defined by the Pet Store application. An API Document includes only the schema, and does not include any details on where the service is published or how to route to it.

The Pet Store application serves its Swagger File (OpenAPI Schema) via HTTP GET /swagger.json. Let’s register this schema with the Gloo Portal operator by creating an APIDoc:

cat <<EOF | kubectl apply -f -
kind: APIDoc
  name: petstore-schema
  namespace: default
  ## specify the type of schema provided in this APIDoc.
  ## openApi is only option at this time.
      # we use a fetchUrl here to tell the Gloo Portal
      # to fetch the schema contents directly from the petstore service.
      # configmaps and inline strings are also supported.
      fetchUrl: http://petstore.default:8080/swagger.json


Once the API Doc has been created, we can verify that the Gloo Portal has processed it by checking its status:

kubectl get apidoc -n default petstore-schema -oyaml
kind: APIDoc
# ...truncated for brevity
  description: A sample API that uses a petstore as an example to demonstrate features
    in the swagger-2.0 specification
  displayName: Swagger Petstore
  observedGeneration: "2"
    - operationId: addPet
      path: /api/pets
      verb: POST
    - operationId: deletePet
      path: /api/pets/{id}
      verb: DELETE
    - operationId: findPetById
      path: /api/pets/{id}
      verb: GET
    - operationId: findPets
      path: /api/pets
      verb: GET
  state: Succeeded
  version: 1.0.0

When we see the Doc in a Succeeded state, it means its API operations can now be included in an API Product. You can also create an API Doc by using the Admin Dashboard.

Gloo Portal requires the operationId field on all of the operations in an OpenAPI document. While this field is optional in the OpenAPI specification, Gloo Portal uses it to assign API Documents to API Products. An operation without an operationId will cause the API Document to enter the Invalid state.

Create an API Product

Let’s create a simple API Product. API Products provide the means of bundling APIs into a Version. Each Version in an API Product can be selective about which operations in an API Document are exposed by the product version.

The API Product we’ll be creating here will have a single version called v1 and it will include all operations from the Pet Store API Doc we just created.

API Product versions also define the route(s) to a service that is serving the operations defined in the API Document. Routes can be specified on a per-operation basis, or through a default route associated with the API Product version.

The API Product version we’ll be creating does not define any specific operations from the apiDoc, so all operations will be included.

Apply the API Product to the cluster:

cat << EOF | kubectl apply -f -
kind: APIProduct
  name: petstore-product
  namespace: default
    app: petstore
    description: Petstore Product
    title: Petstore Product
  # Specify one or more version objects that will each include a list
  # of APIs that compose the version and routing for the version  
  - name: v1
    # Specify the API Doc(s) that will be included in the Product
    # each specifier can include a list of individual operations
    # to import from the API Doc.
    # If none are listed, all the 
    # operations will be imported from the doc. 
    - apiDoc:
        name: petstore-schema
        namespace: default
    # Each imported operation must have a 'route' associated with it.
    # Here we define a route that will be used by default for all the selected APIProduct version operations.
    # You can also set overrides for this route on each individual operation.
    # A route must be provided for every Operation to enable routing for an API Product.  
          - kube:
              name: petstore
              namespace: default
              port: 8080
    # You can add arbitrary tags to an APIProduct version. 
    # Users will be able to search for APIs based on the available tags when they log into a portal application.
      stable: {}

We can verify that our product was accepted into the system by checking its status.state:

kubectl get -n default petstore-product -ojsonpath='{.status.state}'

The command should result in an output of Succeeded once the product has been created.

The complete status of an API Product gives detailed information, including the translated API Schema.

You can view the complete status by running:

kubectl get -n default petstore-product -oyaml

You can also create an API Product by using the Admin Dashboard.

Create an Environment

The final piece of the puzzle is to create an Environment that will expose our API Product version. The Environment resource defines domains on which to expose the API Products, the versions of an API Product to expose, and a Usage Plan for each API Product. The Usage Plan includes authentication and rate limiting. We will not be defining a Usage Plan for our Pet Store API Product, so unauthenticated access will be allowed.

We are going to create an Environment named dev using the domain and expose v1 of our Pet Store API Product.

cat << EOF | kubectl apply -f -
kind: Environment
  name: dev
  namespace: default
  # If you are using Gloo Edge and the Gateway is listening on a port other than 80, 
  # you need to include a domain in this format: <DOMAIN>:<PORT>.
  # In this example we expect the Gateway to listen on port 32000.
    description: This environment is meant for developers to deploy and test their APIs.
    displayName: Development
  # This field will determine which APIProduct versions are published in this Environment.
  # Each entry represents a selector which contains criteria to match the desired API product versions.
  # Here we use a single selector that will match all APIProducts with the `app: petstore` label in all namespaces;
  # Additionally, we want to select only version of these APIProducts that contain the `stable` tag.
  - namespaces:
    - "*" 
    - key: app
      operator: Equals
      - petstore
      - stable

We can check on the status of our Environment by running the following:

kubectl get environment -n default dev -ojsonpath='{.status.state}'

The command should result in an output of Succeeded once the Environment has been created.

The complete status of an Environment gives detailed information, including the translated API Schema and parsed routing configurations rendered by the Gloo Portal operator.

You can view the complete status by running:

kubectl get -n default dev -oyaml

We can also confirm the Virtual Service which corresponds to our Environment:

kubectl get -n default
NAME   GATEWAYS                                HOSTS                 AGE
dev    ["istio-system/istio-ingressgateway"]   [""]   3m25s
kubectl get -n default
dev       81m

You can also create an Environment by using the Admin Dashboard.

Test our API using cURL

Now that we have exposed our API Product for routing, we should be able to make client requests to the product APIs.

Let’s get the address of the Gateway. Choose the option corresponding to your Ingress Service Type:

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?("http2")].port}')
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?("http2")].nodePort}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?("http2")].nodePort}')
export INGRESS_HOST=$(kubectl -n gloo-system get service gateway-proxy -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n gloo-system get service gateway-proxy -o jsonpath='{.spec.ports[?("http")].port}')
export INGRESS_HOST=$(kubectl get po -l gloo=gateway-proxy -n gloo-system -o jsonpath='{.items[0].status.hostIP}')
export INGRESS_PORT=$(kubectl -n gloo-system get service gateway-proxy -o jsonpath='{.spec.ports[?("http")].nodePort}')
export INGRESS_PORT=$(kubectl -n gloo-system get service gateway-proxy -o jsonpath='{.spec.ports[?("http")].nodePort}')

With the Ingress address, we can now try to call one of our published operations:

curl "http://${INGRESS_HOST}:${INGRESS_PORT}/api/pets" -H "Host:"

We should see the output:


Great! We’ve just seen how the Gloo Portal can publish an API on Istio and Gloo Edge without you needing to directly configure those resources. Let’s now see how to expose our APIs to developers using the Portal resource.

Next steps

Continue on to part 2 of the Getting Started guide to see how the Gloo Portal can generate and publish a developer-facing website with documentation and tooling for interacting with these APIs.


For any questions using the Gloo Portal, please visit the slack channel at

If you’d like to report an issue or bug, please see the Gloo Portal Issues Repository on GitHub.