Degraphql

Related Documentation
Related Resources
TL;DR

Create a KongCustomEntity resource that specifies the entity name in spec.type and any required properties under spec.fields.

Prerequisites

If you don’t have a Konnect account, you can get started quickly with our onboarding wizard.

  1. The following Konnect items are required to complete this tutorial:
    • Personal access token (PAT): Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.
  2. Set the personal access token as an environment variable:

    export KONNECT_TOKEN='YOUR KONNECT TOKEN'
    
  1. Install the Gateway API CRDs before installing Kong Ingress Controller.

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml
    
  2. Create a Gateway and GatewayClass instance to use.

echo "
apiVersion: v1
kind: Namespace
metadata:
  name: kong
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: kong
  annotations:
    konghq.com/gatewayclass-unmanaged: 'true'
spec:
  controllerName: konghq.com/kic-gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong
spec:
  gatewayClassName: kong
  listeners:
  - name: proxy
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
         from: All
" | kubectl apply -n kong -f -

Use the Konnect API to create a new CLUSTER_TYPE_K8S_INGRESS_CONTROLLER Control Plane:

CONTROL_PLANE_DETAILS=$(curl -X POST "https://us.api.konghq.com/v2/control-planes" \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "name": "My KIC CP",
       "cluster_type": "CLUSTER_TYPE_K8S_INGRESS_CONTROLLER"
     }')

We’ll need the id and telemetry_endpoint for the values.yaml file later. Save them as environment variables:

CONTROL_PLANE_ID=$(echo $CONTROL_PLANE_DETAILS | jq -r .id)
CONTROL_PLANE_TELEMETRY=$(echo $CONTROL_PLANE_DETAILS | jq -r '.config.telemetry_endpoint | sub("https://";"")')

Create mTLS certificates

Kong Ingress Controller talks to Konnect over a connected secured with TLS certificates.

Generate a new certificate using openssl:

openssl req -new -x509 -nodes -newkey rsa:2048 -subj "/CN=kongdp/C=US" -keyout ./tls.key -out ./tls.crt

The certificate needs to be a single line string to send it to the Konnect API with curl. Use awk to format the certificate:

export CERT=$(awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' tls.crt);

Next, upload the certificate to Konnect:

curl -X POST "https://us.api.konghq.com/v2/control-planes/$CONTROL_PLANE_ID/dp-client-certificates" \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "cert": "'$CERT'"
     }'

Finally, store the certificate in a Kubernetes secret so that Kong Ingress Controller can read it:

kubectl create namespace kong -o yaml --dry-run=client | kubectl apply -f -
kubectl create secret tls konnect-client-tls -n kong --cert=./tls.crt --key=./tls.key
  1. Add the Kong Helm charts:

    helm repo add kong https://charts.konghq.com
    helm repo update
    
  2. Create a file named license.json containing your Kong Gateway Enterprise license and store it in a Kubernetes secret:

    kubectl create namespace kong --dry-run=client -o yaml | kubectl apply -f -
    kubectl create secret generic kong-enterprise-license --from-file=license=./license.json -n kong
    
  3. Create a values.yaml file:

    cat <<EOF > values.yaml
    gateway:
      image:
        repository: kong/kong-gateway
      env:
        LICENSE_DATA:
          valueFrom:
            secretKeyRef:
              name: kong-enterprise-license
              key: license
    EOF
    
  4. Install Kong Ingress Controller using Helm:

    helm install kong kong/ingress -n kong --create-namespace --values ./values.yaml
    
  5. Set $PROXY_IP as an environment variable for future commands:

    export PROXY_IP=$(kubectl get svc --namespace kong kong-gateway-proxy -o jsonpath='{range .status.loadBalancer.ingress[0]}{@.ip}{@.hostname}{end}')
    echo $PROXY_IP
    

Create a GraphQL Service

The degraphql plugin requires an upstream GraphQL API. For this how-to, we’ll use Hasura to create an example GraphQL service:

echo 'apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: hasura
    hasuraService: custom
  name: hasura
  namespace: kong
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hasura
  template:
    metadata:
      labels:
        app: hasura
    spec:
      containers:
      - image: hasura/graphql-engine:v2.38.0
        imagePullPolicy: IfNotPresent
        name: hasura
        env:
        - name: HASURA_GRAPHQL_DATABASE_URL
          value: postgres://user:password@localhost:5432/hasura_data
        - name: HASURA_GRAPHQL_ENABLE_CONSOLE
          value: "true"
        - name: HASURA_GRAPHQL_DEV_MODE
          value: "true"
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        resources: {}
      - image: postgres:15
        name: postgres
        env:
        - name: POSTGRES_USER
          value: "user"
        - name: POSTGRES_PASSWORD
          value: "password"
        - name: POSTGRES_DB
          value: "hasura_data"
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: hasura
  name: hasura
  namespace: kong
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  selector:
    app: hasura
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hasura-ingress-console
  namespace: kong
  annotations:
    konghq.com/strip-path: "true"
spec:
  ingressClassName: kong
  rules:
  - http:
      paths:
      - path: /hasura
        pathType: Prefix
        backend:
          service:
            name: hasura
            port:
              number: 80' | kubectl apply -f -

Once the Hasura Pod is running, bootstrap an API to return contact details using the Hasura API:

curl -X POST -H "Content-Type:application/json" -H "X-Hasura-Role:admin" http://${PROXY_IP}/hasura/v2/query -d '{"type": "run_sql","args": {"sql": "CREATE TABLE contacts(id serial NOT NULL, name text NOT NULL, phone text NOT NULL, PRIMARY KEY(id));"}}'
curl -X POST -H "Content-Type:application/json" -H "X-Hasura-Role:admin" http://${PROXY_IP}/hasura/v2/query -d $'{"type": "run_sql","args": {"sql": "INSERT INTO contacts (name, phone) VALUES (\'Alice\',\'0123456789\');"}}'
curl -X POST -H "Content-Type:application/json" -H "X-Hasura-Role:admin" http://${PROXY_IP}/hasura/v1/metadata -d '{"type": "pg_track_table","args": {"schema": "public","name": "contacts"}}'

Create a Route

Our Hasura API will be exposed using the /contacts path. Create an HTTPRoute or Ingress resource pointing to the hasura Service that we can attach the degraphql plugin to:

Configure the DeGraphQL plugin

The degraphql plugin accepts a single configuration option, graphql_server_path. Create a KongPlugin resource and attach it to the demo-graphql route that you just created:

echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: degraphql-example
  namespace: kong
  annotations:
    kubernetes.io/ingress.class: kong
plugin: degraphql
config:
  graphql_server_path: '/v1/graphql'
" | kubectl apply -f -

Next, apply the KongPlugin resource by annotating the httproute or ingress resource:

The degraphql entity requires you to configure a mapping between paths and GraphQL queries. In this example, we’ll map the /list path to query{ contacts { name } } using the KongCustomEntity CRD. The KongCustomEntity CRD attaches the fields to the KongPlugin specified in the parentRef field.

The following resource tells Kong Ingress Controller to create a degraphql_routes entity in Kong Gateway and attach it to the plugin created by the degraphql-example KongPlugin resource:

echo 'apiVersion: configuration.konghq.com/v1alpha1
kind: KongCustomEntity
metadata:
  namespace: kong
  name: degraphql-route-example
spec:
  type: degraphql_routes
  fields:
    uri: "/list"
    query: "query{ contacts { name } }"
  controllerName: kong
  parentRef:
    group: "configuration.konghq.com"
    kind: "KongPlugin"
    name: "degraphql-example"
' | kubectl apply -f -

Test the Service with the DeGraphQL plugin

To test the degraphql plugin, call the /contacts/list endpoint. The /contacts prefix comes from our Route definition, and the /list segment comes from our degraphql_routes definition.

curl "$PROXY_IP/contacts/list"
curl "$PROXY_IP/contacts/list"

The cURL command should return the data that we inserted at the beginning of this how-to:

{"data":{"contacts":[{"name":"Alice"}]}}

Cleanup

helm uninstall kong -n kong
Something wrong?

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!