As I’ve expressed in a previous post, we are migrating a laravel monolith to nestjs microservices, as such we need an API gateway that can handle both the legacy API and the new API.
While researching, I found this app called Krakend, I know there are others out there who use Tyk.io but what got me interested in krakend is that it can be run in docker, and it only needs a json file for configuration.
I leave this here, because while using the playground it came with really heavy services for monitoring, but because I’m just learning it, I removed most stuff and just kept krakend on my docker-compose file.
For this example I’m using my previous example on laravel / nestjs shared auth, so you can just clone it, and head to the krakend-example
branch to check the files.
In order to accomodate krakend in my project I had to modify my docker-compose file
version: '3'
services:
mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=laraveldb
volumes:
- db-data:/var/lib/mysql:cached
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:cached
- ../:/app:cached
depends_on:
- workspace #must be the same name of the laravel container used above
krakend_ce:
# The :watch image restarts the service automatically when the configuration files change.
# Do not use this image in production, it's meant to speed up your testing and development.
image: devopsfaith/krakend:watch
volumes:
- ./krakend:/etc/krakend
ports:
- "1234:1234"
- "8080:8080"
- "8090:8090"
command: ["run", "-d", "-c", "/etc/krakend/krakend.json"]
redis:
image: redis:alpine
ports:
- "6379:6379"
volumes:
db-data:
I also had to set a HOST
enviroment in my Dockerfile in order for nestJs to be accesible in the docker network.
ENV HOST 0.0.0.0
Before heading to create the Krakend config, I added an API endpoint to my controllers in Laravel & NestJs
For example reasons, I hardcoded the api/v1
//routes/api.php
Route::get('v1/cats',function(){
return response(['message'=>'v1 cats']);
});
//app.controller.ts
@Get('api/v2/cats')
getCats(): any {
return { message: 'v2 Cats' };
}
After adding Krakend in my docker-compose, I had to make a folder for the configuration as you see from the mapped volumes .devocontainer/krakend/
inside it a krakend.json
file.
This is my basic krakend json config file
{
"$schema": "https://www.krakend.io/schema/v3.json",
"version": 3,
"name": "KrakenD - API Gateway",
"timeout": "3000ms",
"cache_ttl": "300s",
"output_encoding": "json",
"debug_endpoint": true,
"echo_endpoint": true,
"endpoints": [
{
"endpoint": "/v1/cats",
"method": "GET",
"output_encoding": "json",
"backend": [
{
"url_pattern": "/api/v1/cats",
"encoding": "json",
"method": "GET",
"extra_config": {
"github.com/devopsfaith/krakend-cors": {
"allow_origins": ["*"],
"allow_methods": ["GET"],
"allow_headers": ["Content-Type"]
}
},
"host": [
"http://nginx"
],
"disable_host_sanitize": true
}
]
},
{
"endpoint": "/v2/cats",
"method": "GET",
"output_encoding": "json",
"backend": [
{
"url_pattern": "/api/v2/cats",
"encoding": "json",
"method": "GET",
"extra_config": {
"github.com/devopsfaith/krakend-cors": {
"allow_origins": ["*"],
"allow_methods": ["GET"],
"allow_headers": ["Content-Type"]
}
},
"host": [
"http://workspace:3000"
],
"disable_host_sanitize": true
}
]
}
]
}
Notes:
Because Docker sets alias on the containers, in order to call them, I had to reference them by their alias.
Using artisan serve
If by any chance, you are using php artisan serve
command from docker, you need to pass the host and port parameters in order for them to be exposed
php artisan serve --host=0.0.0.0 --port=8000
In the krakend.json file, remember to change the host
to the name of the container hosting the laravel app, in my example it would be http://workspace:8000
In order to test that it works, you can head to http://localhost:8080/v1/cats
this answer will come from laravel, if you change to v2
the answer will come from NestJs.