Skip to content

Pubish APIs from CRDs

Old documentation for Hub v1

Kubernetes only!

This is a more advanced topic and requires deeper knowledge of Kubernetes!

Introduction

In this tutorial, you'll learn how to use Kubernetes Custom Resource Definitions with Traefik Hub to manage and publish APIs.

For the purpose of this tutorial, you will use domains generated by Traefik Hub for the API Gateway and Portal.

By the end of this tutorial, you'll have learned how to:

  • Deploy APIs with CRDs
  • Configures access and permissions of APIs and API collections
  • Configure an API Gateway
  • Expose an API Portal
  • Use curl or HTTPIe for sending API requests

Before you begin

Before getting started, make sure you have the following:

1. Install Traefik and the Traefik Hub Agent

In the first step, you will set up Traefik and the Traefik Hub Agent.

Login to Traefik Hub and create your first Agent by selecting Install my first Traefik Hub Agent.

Choose Kubernetes as platform.

Choose Kubernetes as platform

1.1 Add the Traefik Helm repository

Copy the first code block into your terminal and select Enter.

Add Helm repository

1.2 Installing Traefik

This command will:

  • Upgrade the chart to the latest version
  • Will install Traefik via the chart into the namespace hub-agent

Copy the code block into your terminal and hit Enter.

Install Traefik Proxy

1.3. Installing the Traefik Hub Agent

Copy and paste the configuration shown in the Traefik Hub UI into the CLI.

Install the Traefik Hub Agent

1.4 Save the token

Save the token in a secure place!

Select Copy and save your token.

Save the token

Once you are done, select Configuration Done.


2. Configure the Traefik Hub Agent

Name the Agent to api-demo and select Save, followed by selecting Go to the Agent Details.

3. Prepare the demo

Create a directory called hub-demo, this will be your working directory for this tutorial.

All APIs will be deployed into the apps namespace.
In this step, you will create this namespace.

Create a file with the name namespace.yaml in your hub-demo directory with the following content:

---
apiVersion: v1
kind: Namespace
metadata:
  name: apps

Use kubectl to deploy it:

kubectl apply -f namespace.yaml

4. Deploy the demo APIs

Now, that you have created the namespace for your API apps, it's time to deploy the APIs.

Customers API

In your hub-demo directory, create a new directory called customer and change into it.

Now create the following YAML files:

api.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: API
metadata:
  name: customer-api
  namespace: apps
  labels:
    area: customers
    module: crm
spec:
  pathPrefix: "/customers"
  service:
    openApiSpec:
      path: /openapi.yaml
      port:
        number: 3000
    name: customer-app
    port:
      number: 3000
customer.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: customer-data
  namespace: apps
data:
  api.json: |
    {
      "customers": [
        { "id": 1, "firstName": "John", "lastName": "Doe", "points": 100, "status": "bronze" },
        { "id": 2, "firstName": "Jane", "lastName": "Doe", "points": 200, "status": "silver" },
        { "id": 3, "firstName": "John", "lastName": "Smith", "points": 300, "status": "gold" }
      ]
    }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: customer-app
  namespace: apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: customer-app
  template:
    metadata:
      labels:
        app: customer-app
    spec:
      containers:
        - name: api
          image: douglasdtm/json-server:openapi
          args: ["--watch", "/api/api.json", "--static", "/public"]
          imagePullPolicy: IfNotPresent
          volumeMounts:
          - name: api-data
            mountPath: /api
          - name: openapi
            mountPath: /public
      volumes:
        - name: api-data
          configMap:
            name: customer-data
        - name: openapi
          configMap:
            name: customer-apispec

---
apiVersion: v1
kind: Service
metadata:
  name: customer-app
  namespace: apps
  labels:
    app: customer-app
spec:
  type: ClusterIP
  ports:
    - port: 3000
      name: api
  selector:
    app: customer-app
spec.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: customer-apispec
  namespace: apps
data:
  openapi.yaml: |
    openapi: "3.0.0"
    info:
      version: 1.0.0
      title: Customers
      description: OpenAPI specification based on Swagger Petstore (https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore.yaml).
    servers:
      - url: https://api.traefik.localhost
    paths:
      /customers:
        get:
          summary: Get customers
          operationId: getCustomers
          tags:
            - customers
          parameters:
            - name: limit
              in: query
              description: How many items to return at one time (max 100)
              required: false
              schema:
                type: integer
                maximum: 100
                format: int32
          responses:
            '200':
              description: A paged array of customers
              headers:
                x-next:
                  description: A link to the next page of responses
                  schema:
                    type: string
              content:
                application/json:    
                  schema:
                    $ref: "#/components/schemas/Customers"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        post:
          summary: Create a customer
          operationId: createCustomer
          tags:
            - customers
          responses:
            '201':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
      /customers/{customerId}:
        get:
          summary: Info for a specific customer
          operationId: showCustomerById
          tags:
            - customers
          parameters:
            - name: customerId
              in: path
              required: true
              description: The id of the customer
              schema:
                type: string
          responses:
            '200':
              description: Expected response to a valid request
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Customer"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        put:
          summary: Update a customer
          operationId: updateCustomer
          tags:
            - customers
          parameters:
            - name: customerId
              in: path
              required: true
              description: The id of the customer
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        delete:
          summary: Delete a customer
          operationId: deleteCustomer
          tags:
            - customers
          parameters:
            - name: customerId
              in: path
              required: true
              description: The id of the customer
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
    components:
      schemas:
        Customer:
          type: object
          required:
            - id
            - firstName
            - lastName
          properties:
            id:
              type: integer
              format: int64
            firstName:
              type: string
            lastName:
              type: string
            points:
              type: integer
              format: int64
            status:
              type: string
        Customers:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Customer"
        Error:
          type: object
          required:
            - message
          properties:
            message:
              type: string

The following kubectl commands will deploy the API:

kubectl apply -f api.yaml \
              -f customer.yaml \
              -f spec.yaml

Employee API

Go back into your hub-demo directory, and create a new directory called employee.

Once you have created it, change into it and create the following files:

api.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: API
metadata:
  name: employee-api
  namespace: apps
  labels:
    area: internal
    module: crm
spec:
  pathPrefix: "/employees"
  service:
    openApiSpec:
      path: /openapi.yaml
      port:
        number: 3000
    name: employee-app
    port:
      number: 3000
employee.yaml

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: employee-data
  namespace: apps
data:
  api.json: |
    {
      "employees": [
        { "id": 1, "firstName": "John", "lastName": "Doe", "role": "pilot", "homeAirport": "RIC" },
        { "id": 2, "firstName": "Jane", "lastName": "Doe", "role": "engineer", "homeAirport": "CDG" },
        { "id": 3, "firstName": "John", "lastName": "Smith", "role": "attendant", "homeAirport": "DTW" }
      ]
    }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: employee-app
  namespace: apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: employee-app
  template:
    metadata:
      labels:
        app: employee-app
    spec:
      containers:
        - name: api
          image: douglasdtm/json-server:openapi
          args: ["--watch", "/api/api.json", "--static", "/public"]
          imagePullPolicy: IfNotPresent
          volumeMounts:
          - name: api-data
            mountPath: /api
          - name: openapi
            mountPath: /public
      volumes:
        - name: api-data
          configMap:
            name: employee-data
        - name: openapi
          configMap:
            name: employee-apispec

---
apiVersion: v1
kind: Service
metadata:
  name: employee-app
  namespace: apps
  labels:
    app: employee-app
spec:
  type: ClusterIP
  ports:
    - port: 3000
      name: api
  selector:
    app: employee-app
spec.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: employee-apispec
  namespace: apps
data:
  openapi.yaml: |
    openapi: "3.0.0"
    info:
      version: 1.0.0
      title: Employees
      description: OpenAPI specification based on Swagger Petstore (https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore.yaml).
    servers:
      - url: https://api.traefik.localhost
    paths:
      /employees:
        get:
          summary: Get employees
          operationId: getEmployees
          tags:
            - employees
          parameters:
            - name: limit
              in: query
              description: How many items to return at one time (max 100)
              required: false
              schema:
                type: integer
                maximum: 100
                format: int32
          responses:
            '200':
              description: A paged array of employees
              headers:
                x-next:
                  description: A link to the next page of responses
                  schema:
                    type: string
              content:
                application/json:    
                  schema:
                    $ref: "#/components/schemas/Employees"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        post:
          summary: Create a employee
          operationId: createEmployee
          tags:
            - employees
          responses:
            '201':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
      /employees/{employeeId}:
        get:
          summary: Info for a specific employee
          operationId: showEmployeeById
          tags:
            - employees
          parameters:
            - name: employeeId
              in: path
              required: true
              description: The id of the employee
              schema:
                type: string
          responses:
            '200':
              description: Expected response to a valid request
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Employee"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        put:
          summary: Update an employee
          operationId: updateEmployee
          tags:
            - employees
          parameters:
            - name: employeeId
              in: path
              required: true
              description: The id of the employee
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        delete:
          summary: Delete a employee
          operationId: deleteEmployee
          tags:
            - employees
          parameters:
            - name: employeeId
              in: path
              required: true
              description: The id of the employee
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
    components:
      schemas:
        Employee:
          type: object
          required:
            - id
            - firstName
            - lastName
          properties:
            id:
              type: integer
              format: int64
            firstName:
              type: string
            lastName:
              type: string
            role:
              type: string
            homeAirport:
              type: string
        Employees:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Employee"
        Error:
          type: object
          required:
            - message
          properties:
            message:
              type: string

The following kubectl commands will deploy the API:

kubectl apply -f api.yaml \
              -f employee.yaml \
              -f spec.yaml

Flight API

Go back into your hub-demo directory, and create a new directory called flight.

Once you have created it, change into it and create the following files:

api.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: API
metadata:
  name: flight-api
  namespace: apps
  labels:
    area: flights
    module: erp
spec:
  pathPrefix: "/flights"
  service:
    openApiSpec:
      path: /openapi.yaml
      port:
        number: 3000
    name: flight-app
    port:
      number: 3000
flight.yaml

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: flight-data
  namespace: apps
data:
  api.json: |
    {
      "flights": [
        { "id": 1, "code": "TL123", "src": "JFK", "dest": "CDG" },
        { "id": 2, "code": "TL234", "src": "CDG", "dest": "JFK" },
        { "id": 3, "code": "TL345", "src": "CDG", "dest": "LYS" }
      ]
    }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: flight-app
  namespace: apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flight-app
  template:
    metadata:
      labels:
        app: flight-app
    spec:
      containers:
        - name: api
          image: douglasdtm/json-server:openapi
          args: ["--watch", "/api/api.json", "--static", "/public"]
          imagePullPolicy: IfNotPresent
          volumeMounts:
          - name: api-data
            mountPath: /api
          - name: openapi
            mountPath: /public
      volumes:
        - name: api-data
          configMap:
            name: flight-data
        - name: openapi
          configMap:
            name: flight-apispec

---
apiVersion: v1
kind: Service
metadata:
  name: flight-app
  namespace: apps
  labels:
    app: flight-app
spec:
  type: ClusterIP
  ports:
    - port: 3000
      name: api
  selector:
    app: flight-app
spec.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: flight-apispec
  namespace: apps
data:
  openapi.yaml: |
    openapi: "3.0.0"
    info:
      version: 1.0.0
      title: Flights
      description: OpenAPI specification based on Swagger Petstore (https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore.yaml).
    servers:
      - url: https://api.traefik.localhost
    paths:
      /flights:
        get:
          summary: Get flights
          operationId: gettFlights
          tags:
            - flights
          parameters:
            - name: limit
              in: query
              description: How many items to return at one time (max 100)
              required: false
              schema:
                type: integer
                maximum: 100
                format: int32
          responses:
            '200':
              description: A paged array of flights
              headers:
                x-next:
                  description: A link to the next page of responses
                  schema:
                    type: string
              content:
                application/json:    
                  schema:
                    $ref: "#/components/schemas/Flights"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        post:
          summary: Create a flight
          operationId: createFlight
          tags:
            - flights
          responses:
            '201':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
      /flights/{flightId}:
        get:
          summary: Info for a specific flight
          operationId: showFlightById
          tags:
            - flights
          parameters:
            - name: flightId
              in: path
              required: true
              description: The id of the flight
              schema:
                type: string
          responses:
            '200':
              description: Expected response to a valid request
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Flight"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        put:
          summary: Update a flight
          operationId: updateFlight
          tags:
            - flights
          parameters:
            - name: flightId
              in: path
              required: true
              description: The id of the flight
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        delete:
          summary: Delete a flight
          operationId: deleteFlight
          tags:
            - flights
          parameters:
            - name: flightId
              in: path
              required: true
              description: The id of the flight
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
    components:
      schemas:
        Flight:
          type: object
          required:
            - id
            - name
          properties:
            id:
              type: integer
              format: int64
            code:
              type: string
            source:
              type: string
            destination:
              type: string
        Flights:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Flight"
        Error:
          type: object
          required:
            - message
          properties:
            message:
              type: string

The following kubectl commands will deploy the API:

kubectl apply -f api.yaml \
              -f flight.yaml \
              -f spec.yaml

Ticket API

Go back into your hub-demo directory, and create a new directory called ticket.

Once you have created it, change into it and create the following files:

api.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: API
metadata:
  name: ticket-api
  namespace: apps
  labels:
    area: support
    module: crm
spec:
  pathPrefix: "/tickets"
  service:
    openApiSpec:
      path: /openapi.yaml
      port:
        number: 3000
    name: ticket-app
    port:
      number: 3000
ticket.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ticket-data
  namespace: apps
data:
  api.json: |
    {
      "tickets": [
        { "id": 1, "flightCode": "TL123", "fare": 500, "class": "first", "available": 5, "total": 20 },
        { "id": 2, "flightCode": "TL234", "fare": 200, "class": "economy", "available": 2, "total": 5 },
        { "id": 3, "flightCode": "TL345", "fare": 300, "class": "business", "available": 3, "total": 10 }
      ]
    }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ticket-app
  namespace: apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ticket-app
  template:
    metadata:
      labels:
        app: ticket-app
    spec:
      containers:
        - name: api
          image: douglasdtm/json-server:openapi
          args: ["--watch", "/api/api.json", "--static", "/public"]
          imagePullPolicy: IfNotPresent
          volumeMounts:
          - name: api-data
            mountPath: /api
          - name: openapi
            mountPath: /public
      volumes:
        - name: api-data
          configMap:
            name: ticket-data
        - name: openapi
          configMap:
            name: ticket-openapi

---
apiVersion: v1
kind: Service
metadata:
  name: ticket-app
  namespace: apps
  labels:
    app: ticket-app
spec:
  type: ClusterIP
  ports:
    - port: 3000
      name: api
  selector:
    app: ticket-app
spec.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ticket-openapi
  namespace: apps
data:
  openapi.yaml: |
    openapi: "3.0.0"
    info:
      version: 1.0.0
      title: Tickets
      description: OpenAPI specification based on Swagger Petstore (https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore.yaml).
    servers:
      - url: https://api.traefik.localhost
    paths:
      /tickets:
        get:
          summary: Get tickets
          operationId: getTickets
          tags:
            - tickets
          parameters:
            - name: limit
              in: query
              description: How many items to return at one time (max 100)
              required: false
              schema:
                type: integer
                maximum: 100
                format: int32
          responses:
            '200':
              description: A paged array of tickets
              headers:
                x-next:
                  description: A link to the next page of responses
                  schema:
                    type: string
              content:
                application/json:    
                  schema:
                    $ref: "#/components/schemas/Tickets"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        post:
          summary: Create a ticket
          operationId: createTicket
          tags:
            - tickets
          responses:
            '201':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
      /tickets/{ticketId}:
        get:
          summary: Info for a specific ticket
          operationId: showTicketById
          tags:
            - tickets
          parameters:
            - name: ticketId
              in: path
              required: true
              description: The id of the ticket
              schema:
                type: string
          responses:
            '200':
              description: Expected response to a valid request
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Ticket"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        put:
          summary: Update a ticket
          operationId: updateTicket
          tags:
            - tickets
          parameters:
            - name: ticketId
              in: path
              required: true
              description: The id of the ticket
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        delete:
          summary: Delete a ticket
          operationId: deleteTicket
          tags:
            - tickets
          parameters:
            - name: ticketId
              in: path
              required: true
              description: The id of the ticket
              schema:
                type: string
          responses:
            '200':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
    components:
      schemas:
        Ticket:
          type: object
          required:
            - id
            - flightCode
          properties:
            id:
              type: integer
              format: int64
            flightCode:
              type: string
            fare:
              type: integer
              format: int64
            class:
              type: string
            available:
              type: integer
              format: int64
            total:
              type: integer
              format: int64
        Tickets:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Ticket"
        Error:
          type: object
          required:
            - message
          properties:
            message:
              type: string

The following kubectl commands will deploy the API:

kubectl apply -f api.yaml \
              -f ticket.yaml \
              -f spec.yaml

5. Configure API access

In step five, you will configure the access permissions for the API Gateway.

For doing so, change back into the top level directory of this tutorial, hub-demo and create a file called api-access.yaml with the following content:

api-access.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
  name: customer-admin
spec:
  groups:
    - ignored-atm
  apiSelector:
    matchLabels:
      area: customers

---
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
  name: crm-apis
spec:
  groups:
    - ignored-atm
  apiSelector:
    matchLabels:
      module: crm

---
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
  name: crm-collections
spec:
  groups:
    - ignored-atm
  apiCollectionSelector:
    matchLabels:
      module: crm

---
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
  name: custom-pick
spec:
  groups:
    - ignored-atm
  apiSelector:
    matchExpressions:
      - key: area
        operator: In
        values:
          - flights
          - support

Use kubectl to deploy it:

kubectl apply -f api-access.yaml

6. Configure the API Gateway

Now it is time to configure the Gateway for your APIs.

In Traefik Hub, an API Gateway is the main entry point to all your APIs.

This is where you define the public domains for your APIs and which APIs and API collections you want to expose via an APIAccess CRD.

For doing so, change back into the top level directory of this tutorial, hub-demo and create a file called api-gateway.yaml with the following content:

api-gateway.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: APIGateway
metadata:
  name: my-gateway
  labels:
    area: crm
spec:
  apiAccesses:
    - customer-admin
    - crm-collections
    - crm-apis
    - custom-pick

Use kubectl to deploy it:

kubectl apply -f api-gateway.yaml

6.1 Access an API via the Gateway

kubectl get apigateway -n apps

Follow the URL in the output plus the API prefix you want to reach, for example

API Gateway in browser

7. Configure the API Portal

In Traefik Hub, the API Portal is the landing page of an API or an API collection.

In the Portal, the consumer can view a representation of the OpenAPI specification and effortlessly interact and try out every API operation.

For doing so, change back into the top level directory of this tutorial, hub-demo and create a file called api-portal.yaml with the following content:

api-portal.yaml
---
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortal
metadata:
  name: my-preview-portal
spec:
  title: "Traefik Airlines"
  description: "Traefik Airlines API Portal"
  apiGateway: my-gateway

Use kubectl to deploy it:

kubectl apply -f api-portal.yaml

7.1 Access the API Portal

kubectl get apiportal -n apps

Follow the URL in the output

API Portal in browser


8. Sending API requests

In the last part of this tutorial, you will use curl or HTTPIe to interact with the deployed Customers API.

curl

curl is s widely-used by developers for quickly testing REST APIs in the command line.

The following command will perform the request and output the response body:

curl -v --location https://parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev/customers/customers

Which will show:

curl -v --location https://parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev/customers/customers
*   Trying 52.56.86.87:443...
* Connected to parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev (52.56.86.87) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* [CONN-0-0][CF-SSL] (304) (OUT), TLS handshake, Client hello (1):
* [CONN-0-0][CF-SSL] (304) (IN), TLS handshake, Server hello (2):
* [CONN-0-0][CF-SSL] (304) (IN), TLS handshake, Unknown (8):
* [CONN-0-0][CF-SSL] (304) (IN), TLS handshake, Certificate (11):
* [CONN-0-0][CF-SSL] (304) (IN), TLS handshake, CERT verify (15):
* [CONN-0-0][CF-SSL] (304) (IN), TLS handshake, Finished (20):
* [CONN-0-0][CF-SSL] (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=*.yzxs6p9v.preview.traefikhub.dev
*  start date: Feb 28 11:52:59 2023 GMT
*  expire date: May 29 11:52:58 2023 GMT
*  subjectAltName: host "parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev" matched cert's "*.yzxs6p9v.preview.traefikhub.dev"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /customers/customers]
* h2h3 [:scheme: https]
* h2h3 [:authority: parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev]
* h2h3 [user-agent: curl/7.87.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x12b010a00)
> GET /customers/customers HTTP/2
> Host: parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev
> user-agent: curl/7.87.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200
< access-control-allow-credentials: true
< cache-control: no-cache
< content-type: application/json; charset=utf-8
< date: Fri, 31 Mar 2023 13:04:11 GMT
< etag: W/"152-YYUUBmMg0FfHP0BwM9kbIO/ll84"
< expires: -1
< pragma: no-cache
< vary: Origin, Accept-Encoding
< x-content-type-options: nosniff
< x-powered-by: Express
< content-length: 338
<
[
  {
    "id": 1,
    "firstName": "John",
    "lastName": "Doe",
    "points": 100,
    "status": "bronze"
  },
  {
    "id": 2,
    "firstName": "Jane",
    "lastName": "Doe",
    "points": 200,
    "status": "silver"
  },
  {
    "id": 3,
    "firstName": "John",
    "lastName": "Smith",
    "points": 300,
    "status": "gold"
  }
* Connection #0 to host parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev left intact
]%

HTTPie

HTTPIe make it painless to test and debug APIs, HTTP servers, and web services.

In the following example, you will run a GET request against the /customers endpoint of the example API.

https https://parental-camel-vamdrm.yzxs6p9v.preview.traefikhub.dev/customers/customers

This will create the following (colorized and formatted) output:

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Content-Length: 338
Content-Type: application/json; charset=utf-8
Date: Fri, 31 Mar 2023 13:14:12 GMT
Etag: W/"152-YYUUBmMg0FfHP0BwM9kbIO/ll84"
Expires: -1
Pragma: no-cache
Vary: Origin, Accept-Encoding
X-Content-Type-Options: nosniff
X-Powered-By: Express

[
    {
        "firstName": "John",
        "id": 1,
        "lastName": "Doe",
        "points": 100,
        "status": "bronze"
    },
    {
        "firstName": "Jane",
        "id": 2,
        "lastName": "Doe",
        "points": 200,
        "status": "silver"
    },
    {
        "firstName": "John",
        "id": 3,
        "lastName": "Smith",
        "points": 300,
        "status": "gold"
    }
]

Summary

In this tutorial, you learned how to:

  • Deploy APIs with CRDs
  • Configures access and permissions of APIs and API collections
  • Configure an API Gateway
  • Expose an API Portal
  • Use HTTPIe or curl for sending API requests

What's next