From Design-First to Automated Deployment with OpenAPI
Tags: kubernetes, openapi
Published: 2022-04-26 07:19:40

Being an API-first organization is becoming a must as organizations need to build APIs to enable consumers (internal or external) to extend the functionality of their systems, share data across organizations and build customized experiences.

The microservices architecture — building services that perform only one function, as opposed to covering an entire area of functionality — provides the agile and efficient building workflows needed to deliver seamless customer experiences.

Finally, Kubernetes, a container orchestration system, has been an extremely popular choice for orchestrating those microservices. It has helped adopt the organizational agile structure into the API development process, but has inherently introduced a new set of challenges.

Current API development processes require developers to adhere to an organizational set of best practices — if they even exist and assuming that developers have read those best practices and are implementing them — that can only recommend, but not enforce the best practices, giving turn to inconsistent API quality, (slow) developer experience and configuration control.

In this article we will discuss how you can address these challenges by implementing a design-first approach in your APIs and automating their deployment.

## Design-First

Most developers have been following a code-first approach to build their APIs. That is, implement the API first, and everything from documentation — usually [code-generated OpenAPI specifications](https://swagger.io/tools/swagger-codegen/) used with [Swagger](https://swagger.io/docs/) — to the organization’s policy requirements (security, etc) have come _after_ the fact.

The code-first approach has increased the speed of the development itself, but it has compromised the consistent experience between the organization’s APIs and their quality.

To introduce consistency and quality to a code-first approach, organizations have usually introduced blockers in the deployment process (for example, requiring an API team approval) and in turn slowing down going to production.

Going design-first means you start by designing your API — writing how your APIs should behave and translating that to the OpenAPI specification — and, once it has been agreed upon, you would then start writing the code to implement the designed behavior of the API.

Design-first approach enables you to include multiple stakeholders from your organization early in the API design process. Additionally, there are tools that can validate the designed specification, which reduces risks of failure, improves consistency and enforces required aspects of the APIs.

## Design-First in Practice

A lot of companies have tried design-first methodologies, but have failed to maintain them after a while because they either could not set up the right process, or it was extremely time consuming or tedious.

In the following walkthrough, we will use three tools to help us set up the process required to go from design to implementation with little overhead. Our design-first approach will be the following:

1. We’ll use [SwaggerHub](https://swagger.io/tools/swaggerhub/) to create our OpenAPI document which allows us to automatically validate the designed API against our standardization rules. The design-time validation ensures that the new API will be consistent with other APIs across the organization. Additionally, we can specify validation rules, to ensure operational consistency across our microservices landscape.

2. After that, the designed spec would go into a git repository that will help having a single source of truth of our APIs. This git repository will be connected to ArgoCD, which can then ensure that the cluster is up-to-date with the repository.

3. Finally, ArgoCD will use Kusk-gateway, an OpenAPI driven Kubernetes gateway, to deploy the API so developers can start implementing the services.

The process would look like the following diagram:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u84t2z915cid55e2jgzo.png)

## Walkthrough

Enough talk — let’s see this in action — here comes a step-by-step walkthrough to get this in place for the automated deployment and execution of OpenAPI specifications in your cluster of choice!

Let’s start with setting things up for our APIOps-powered development!

**1. Setting up a Github repository**

[Create a Github repository](https://github.com/new) that we will use to put our OpenAPI specifications in and synchronize them with the deployed API in the cluster.

After the repository is created, create a new folder in the repository with the name api. This is where we will put our OpenAPI spec.

For that, run the following commands

```
mkdir api # folder where the OpenAPI spec will go to
touch api/.gitkeep
git add . git commit -m “Initial commit”
git push origin main
```

**2. Create a new API in SwaggerHub**

In SwaggerHub, on the top left menu, click on “Create New API”

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4rm3b3nb8cbcy2jw2n47.png)

Fill in the form as shown below:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sal1wv1msf8bg47rjmjs.png)

Once the API is created, let’s write an example API to deploy. Copy the spec below and paste it in your SwaggerHub editor.
  
{% embed https://gist.github.com/aabedraba/b5ffa517b495b67256ce47d280ece8f1 %}

OpenAPI allows extending the spec by use of decorators. To extend the OpenAPI specification, you just need to create a new section in the spec that starts with “x-”. In the spec above, you can see that we have used x-kusk to add Kusk-gateway’s configurations.

**3. Connect SwaggerHub to your Github repository**

To deploy it to our Github repository you will need to hover on the _Sync_ button as seen below and click on _Setup Integration_.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wpfu715lfsea9sz2i0xf.png)

Choose the _Github Sync_ integration and click on _Next_.

In the next window, click on _Connect to Github_ and follow the procedure to connect it. Remember to choose the right repository (the one we just created in the first step).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udq8z2wegtlrx5t8quls.png)

Now fill out the rest of the form as seen below. After that click on the _Create and Execute_ button and click on _Done_ in the next window.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bidkj5mi0l2q3cs5dn30.png)

To check if the integration works, click on the _Sync_ button as seen below, _Push the changes_ and you should see the updates in your Github repository!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9csvqgwip115kcn62h3.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acj0ewfknfseqw28c2b4.png)

**4. Install Kusk-gateway in your Kubernetes cluster**  

Follow the Kusk-gateway [installation guide](https://kubeshop.github.io/kusk-gateway/installation/). 

**5. Install ArgoCD in your Kubernetes cluster**

Follow the ArgoCD [installation guide](https://argo-cd.readthedocs.io/en/stable/getting_started/).

**6.Configure ArgoCD to use Kusk-gateway**

ArgoCD allows the use of [plugins](https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/) that we will use to install Kusk’s CLI tool with, so that when our Github repository is updated, ArgoCD can run the CLI tool to generate the YAML manifests from the OpenAPI specification and apply them to the cluster. 

Create a deployment patch manifest patch.yaml, this will be of type JSON-patch:

{% embed https://gist.github.com/aabedraba/401802f2556169e258d1fa6f0f4a99ea %}

And apply it with the following command:

```
kubectl patch deployments.apps -n argocd argocd-repo-server --type json --patch-file patch.yaml
```


Now let’s add Kusk CLI to ArgoCD’s plugin ConfigMap. Create the file
`argocd-plugins.yaml`

{% embed https://gist.github.com/aabedraba/d51d332766ba71400f95661fbec67121 %}

As you can see here, we’re using the command `kgw api generate` which creates the Custom Resources (manifests) that ArgoCD will then add to our cluster. Apply the patch with the command:

```sh
kubectl patch -n argocd configmaps argocd-cm --patch-file argocd-plugin.yaml
```

Finally, create the ArgoCD application that will manage your API’s gateway deployment.

Create the file `kusk-gateway-application.yaml`

{% embed https://gist.github.com/aabedraba/27cb64c5b06130fbabca8bc37e13285f %}

Notice that we have defined `path: api` which is the folder in the Github repository with the `api-spec.yaml` from the steps earlier. We have also defined the `.destination.namespace` to be `default`, which is where the gateway should be deployed in the cluster. And apply it with

```sh
kubectl apply -f kusk-gateway-application.yaml
```

**7. Run the initial ArgoCD sync and check your cluster**

On ArgoCD’s dashboard, we will now see the newly created application. Let’s click to get into it and sync our API.

![ArgoCD's dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nuveuv82ldtnbboqkmdy.png)

And now click on _Sync_ to create the gateway for the first time‍.

![Clicking on Sync in ArgoCD's dashbaord](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rwaf35b1u9t5zu4mcgqa.png)

And voilà, there’s our newly created gateway created and managed by ArgoCD with every new update on the OpenAPI spec in the Github repository!

![ArgoCD's dashboard showing a new API has been created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eh8nlnmwocki4hq97y6x.png)

**8. Consuming the Deployed API**

In our API we have configured Kusk-gateway to mock our single endpoint, so we can have a testable endpoint before implementing the service. It uses OpenAPIs [example section](https://swagger.io/docs/specification/adding-examples/) to use as a response mock of the API.

For that we will have to get the Kusk-gateway API endpoint, which you can find by running
 
```sh
kubectl get svc -l "app.kubernetes.io/component=envoy-svc" --namespace kusk-system
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z2llysqj1n0vjv0khb0r.png)

Copy the External IP from the result and query the /hello path defined in our OpenAPI spec:

```sh
$ curl 127.0.0.1/hello
“Hello world!”
```

And we are set to start implementing the API!

## Wrapping up

This flow of programmatic API design we call it the APIOps, which combined with GitOps philosophy (having your repository as a single source of truth, combining it with CI/CD pipeline) provide a powerful alternative to a more traditional code-first approach not so closely aligned with the lifecycle of Kubernetes applications.

Let us know what you think about this method, we’re open to hearing your feedback in our [Discord server](https://discord.gg/uNuhy6GDyn)!

Check [Kusk-gateway on GitHub](https://github.com/kubeshop/kusk-gateway) and [SwaggerHub](https://swagger.io/tools/swaggerhub/)!

You can also check the [webinar on this article](https://smartbear.com/resources/webinars/microservices-kubernetes-from-design-first-to-auto/) if you want to _see_ the action yourself!

Thank you!