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.

Prerequisites

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 \
  https://raw.githubusercontent.com/solo-io/gloo/v1.9.0-beta8/example/petstore/petstore.yaml
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 -
apiVersion: portal.gloo.solo.io/v1beta1
kind: APIDoc
metadata:
 name: petstore-schema
 namespace: default
spec:
 ## specify the type of schema provided in this APIDoc.
 ## openApi is only option at this time.
 openApi:
   content:
     # 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

EOF

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
apiVersion: portal.gloo.solo.io/v1beta1
kind: APIDoc
# ...truncated for brevity
status:
  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"
  openApi:
    operations:
    - 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 route configuration depends on the type of gateway technology we are using.

For Gloo Edge Enterprise, the preferred way of configuring a routing destination is to use an Upstream. If you have Upstream Discovery configured in Gloo Edge, then you should already have an Upstream for the petstore service. If not, we can easily create one:

cat << EOF | kubectl apply -f -
apiVersion: gloo.solo.io/v1
kind: Upstream
metadata:
  name: default-petstore-8080
  namespace: gloo-system
spec:
  kube:
    serviceName: petstore
    serviceNamespace: default
    servicePort: 8080
EOF

This assumes that you have installed Gloo Edge Enterprise to the gloo-system namespace, or that the namespace is watched by Gloo Edge. You should adapt the above configuration if that is not the case.

Now we can create our APIProduct and use the Upstream as a backend for out route:

cat << EOF | kubectl apply -f -
apiVersion: portal.gloo.solo.io/v1beta1
kind: APIProduct
metadata:
  name: petstore-product
  namespace: default
  labels:
    app: petstore
spec:
  displayInfo: 
    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  
  versions:
  - name: v1
    apis:
    # 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.  
    gatewayConfig:
      route:
        inlineRoute:
          backends:
          - upstream:
              name: default-petstore-8080
              namespace: gloo-system
    # 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.
    tags:
      stable: {}
EOF

If you are integrating Gloo Portal with Istio directly, the simplest way of configuring a route is to just reference the Kubernetes service you want to send traffic to.

cat << EOF | kubectl apply -f -
apiVersion: portal.gloo.solo.io/v1beta1
kind: APIProduct
metadata:
  name: petstore-product
  namespace: default
  labels:
    app: petstore
spec:
  displayInfo: 
    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  
  versions:
  - name: v1
    apis:
    # 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.  
    gatewayConfig:
      route:
        inlineRoute:
          backends:
          - 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.
    tags:
      stable: {}
EOF

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

kubectl get apiproducts.portal.gloo.solo.io -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 apiproducts.portal.gloo.solo.io -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 api.example.com and expose v1 of our Pet Store API Product.

cat << EOF | kubectl apply -f -
apiVersion: portal.gloo.solo.io/v1beta1
kind: Environment
metadata:
  name: dev
  namespace: default
spec:
  domains:
  # 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>.
  - api.example.com
  displayInfo:
    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.
  apiProducts:
  - namespaces:
    - "*" 
    labels:
    - key: app
      operator: Equals
      values:
      - petstore
    versions:
      tags:
      - stable
EOF

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 environments.portal.gloo.solo.io -n default dev -oyaml

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

kubectl get virtualservices.gateway.solo.io -n default
NAME      AGE
dev       81m
kubectl get virtualservices.networking.istio.io -n default
NAME   GATEWAYS                                HOSTS                 AGE
dev    ["istio-system/istio-ingressgateway"]   ["api.example.com"]   3m25s

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 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[?(@.name=="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[?(@.name=="http")].nodePort}')
export INGRESS_HOST=127.0.0.1
export INGRESS_PORT=$(kubectl -n gloo-system get service gateway-proxy -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')
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[?(@.name=="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[?(@.name=="http2")].nodePort}')
export INGRESS_HOST=127.0.0.1
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].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: api.example.com"

We should see the output:

[{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]

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.

Questions

For any questions using the Gloo Portal, please visit the Solo.io slack channel at https://slack.solo.io.

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