API easter eggs

Or a cool guide for writing plugins for Kong API Gateway

Kolyubyakin Max
Jun 2, 2020 · 8 min read
Image for post
Image for post
Original photo by Marcreation on Unsplash

Intro

Games always had something in them: you felt the real spirit of exploration, you rushed with joy to your friends just to seat nearby and watch them play! And I bet that all of us had a brilliant idea of a game that everyone would love (if we had a chance to implement it). Becoming an astronaut was never an option, as there was always a choice to become a Game Developer.

Now, 15 years later, I am actually happy that my dreams have only partially come true. I am a developer, but with less “blood, sweat and pixels”. Instead of creating fancy drawn worlds, I have been creating new web ecosystems, platforms and APIs. It definetly sounds like a more boring job, but games have taught me that there is always field for fantasy and exploration. Especially, where it’s least expected.

So what if I told you, that APIs could also have some Easter Eggs? 🐣

Of course I am not talking about unplanned security holes, 0-day vulnerabilities or public APIs, where the main easter egg is the outdated documentation. Technically they count, but I would suggest a more positive approach. Let’s include some fun in our API responses!

In order to do that, we will write our own Lua plugin for Kong API Gateway. Don’t worry if you are not familiar with Lua or Kong. It took me just one working day to write a much more complex working plugin without any previous knowledge. Plus I’ll give a brief explanation and share some useful links to make your life easier. In any case, these tools may be a great addition to your technical arsenal, so I recommend you to spend some time afterwards to get to know them closer. If you are familiar with Kong and Lua, you may skip the next abstract and jump straight to Preparing to cook.

Kong and Lua

Image for post
Image for post

Kong Gateway 🦍 is the the world’s most popular open source API gateway. It is cloud-native, super fast, scalable and extendable. Kong itself extends underlying OpenResty web platform (based on LuaJIT), which runs on the ultra-performant Nginx core (written in C). Kong can run on any platform and in any environment: for example, it’s widely used as an Ingress controller for Kubernetes cluster. But the true power of Kong Gateway is the rich ecosystem of ready-to-use plugins which cover all the important cases: authentication, bot detection, proxy caching, rate limiting, request termination and so on. There are plenty of various useful examples on Kong Github. Though, before diving into source code I would strongly recommend to read official plugin development guide together with an article on declarative configuration and dbless mode.

It’s very important to understand, that Kong is much more than a perfect API Gateway. Kong is a full-fledged open-core API platform for powering of all your APIs and microservices. Kong is a prefect example of an innovative company which moves forward together with its open source community.

Image for post
Image for post

Lua 🌝 is a powerful, efficient, lightweight, embeddable scripting language. It is widely used in web (OpenResty, Redis, etc.) and is loved in gaming industry (WoW, Dark Souls, Star Wars series, etc.). As for me, that sounds like a perfect combination!

Here is a simple Lua tutorial to get started, but for more detailed information you can use official reference manual. It’s not required to read any of the above as our plugin code will be deadly simple. And last but not least, we will use LuaRocks package manager for plugin integration into Kong.

Preparing to cook

#1 Disco 💃🏿🕺: Any good APIs must know how to make you dance (and I am not talking about dancing around with their documentation). When anyone will add “Make-Me: dance” header to GET or HEAD API request, we will return them a link with an incendiary dance.

#2 Jackpot 💰: We will count all the incoming requests and every N responses will contain a special header “You-Have-Won: a prize”. A prize must be randomly chosen and must be something trendy that anyone would like to have.

Water is boiling

src/
access.lua
handler.lua
header_filter.lua
schema.lua
docker-compose.yml
kong-easter-eggs-1.0.0-3.rockspec
kong.tpl.yml
run.sh

Plugin sources live in src folder only. .rockspec file is a specification for luarocks package manager. docker-compose.yml and run.sh are used in plugin development and testing. kong.tpl.yml is a template for our declarative configuration.

Kong plugin file structure has some strict rules. There must always handler.luaentry point file and schema.lua , where plugin configuration is described. access.lua and header_filter.lua are our custom plugin files. They could have any name, but it’s a good practice to name them like that to reflect the lifecycle of requests in Kong.

After setting of project layout we need to create declarative configuration for Kong to start with:

cp kong.tpl.yml kong.yml 

We will now modify kong.yml to have the following configuration:

We have just added Nanoservice with named /root to our Kong API Configuration. We have also set some parameters like dance_link to our kong-easter-eggs plugin.

Note: Microservices are a doubtful trend now, so we need a fresh cool title. Nanoservice title has nothing to do with the size of a service, it’s just a great API service created in the Nano text editor.

All of kong plugin parameters must be described in schema.lua file. Parameters may have different types (string, number, array, etc.), they may be required or have default values.

Let’s now look at our main entry point handler.lua :

Handler contains imports from other files. We also set plugin priority and initialize plugin instance. Our plugin doesn’t depend on any other plugin, so priority value doesn’t matter much. But if we would want to include easter eggs only after authentication, then we would need to choose priority wisely, according to this priority execution list. Within plugin scope execution sequence will be the following: new —> access —> header_filter.

We are totally ready to cook, so let’s start Kong Gateway immediately.

docker-compose up

If everything is fine, we will see something like this in console:

kong_1  | 
kong_1 | No existing manifest. Attempting to rebuild...
kong_1 | kong-easter-eggs 1.0.0-1 is now installed in /home/kong/.luarocks (license: MIT)
kong_1 |
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: using the "epoll" event method
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: openresty/1.15.8.3
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: built by gcc 9.2.0 (Alpine 9.2.0)
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: OS: Linux 4.9.184-linuxkit
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: getrlimit(RLIMIT_NOFILE): 1048576:1048576
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: start worker processes
kong_1 | 2020/05/31 16:49:36 [notice] 67#0: start worker process 71
...

To be totally sure, we can already make a request to Kong, which runs on port 8000 as described in our docker-compose.yml:

curl localhost:8000 -IHTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 648
Connection: keep-alive
Content-Encoding: gzip
Accept-Ranges: bytes
...

Cooking Disco (3 min)

To understand code fully, you need to know that Kong is shipped with a set of helpful tools called PDK — Plugin Development Kit. kong.request and kong.response are examples of modules, provided by Kong to access request information and process responses. Let’s check if our egg is ready:

curl localhost:8000 -H "Make-Me: rich"I'm a teapot. I can't make you rich!

Well… Could be better, but this was expected, as we only taught our APIs dancing techniques. Let’s try again:

curl localhost:8000 -H "Make-Me: dance" -IHTTP/1.1 302 Moved Temporarily
Date: Sun, 31 May 2020 22:19:24 GMT
Content-Type: text/html
Content-Length: 110
Connection: keep-alive
Location: https://youtu.be/dQw4w9WgXcQ
X-Kong-Response-Latency: 0
Server: kong/2.0.3

Awesome! We are redirected to our dancing video in Location header. Disco is ready and now we can check Jackpot.

Hitting Jackpot (6 mins)

You may have spotted, that we use some dirty magic in this line ngx.shared.kong:incr(“requests_count”, 1, 0). Kong runs several worker processes, which run simultaneously. To count incoming requests we need to use the shared memory provided by OpenResty. Kong provides a caching abstraction via kong.cache , but I have chosen to demonstrate another approach. From code we can see that we give out the prize only in case of successful response (≤399) and if there are any prizes. Let’s go and hit our well-deserved jackpot!

curl localhost:8000 -I...
X-Cache: HIT
You-Have-Won: Ticket to Crew Dragon
X-Kong-Upstream-Latency: 557
...

In every third response you will see “You-Have-Won” header. My jackpot is the Ticket to Crew Dragon. Nice one, but I am sure you can do better. Try yourself to see what you will win! APIs must always be rewarding as they really love to be used.

Setting the table

luarocks install kong-easter-eggs

There are several options on how plugins can be installed into Kong. As plugins need to be applied before the start of Kong, you can always create a custom Dockerfile with plugin instructions, based on the official Kong docker images.

Anyway, my fantasy is limited and you may want to add more cool things to your APIs. Here is the GitHub repository for you:

Outro

Anyway, thanks for your time. Stay inspired and share your cool API easter egg ideas in comments, GitHub or LinkedIn.

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Kolyubyakin Max

Written by

Senior IT Witcher ⚔️ Helping to build the best supply-chain automation ecosystem in CloudBlue Connect @ThisisCloudBlue

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Kolyubyakin Max

Written by

Senior IT Witcher ⚔️ Helping to build the best supply-chain automation ecosystem in CloudBlue Connect @ThisisCloudBlue

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store