If you’re regularly working with APIs, you’ll know the struggles of ensuring that they’re secured, protected and managed, as well as building out the core functionality.
If you haven’t already, you’ll want to check out API Management. In essence,
API management is the process of creating and publishing web application programming interfaces (APIs), enforcing their usage policies, controlling access, nurturing the subscriber community, collecting and analyzing usage statistics, and reporting on performance. API Management components provide mechanisms and tools to support developer and subscriber communities
Using the open source Gravitee.io API Management platform (GitHub repo) allows you to create, design and manage the lifecycle of your APIs. With many rich and powerful policies available, you have a huge array of tools and techniques to superpower your APIs, such as:
But sometimes, your designs become so complex that it is almost impossible to know where design and configuration problems occur when they pop up. Don’t panic, Debug Mode is here to the rescue. Debug Mode is a feature that unleashes the power of APIs Publisher, allowing you to design an API, (shadow) deploy it (don’t worry, we’ll explain what shadow deployment is later on), and understand exactly through which policies have been applied to the API call.
In this blog post, we are going to put ourselves in the shoes of an API publisher, looking at an API displaying some weird behaviors. We will walk through a simple example of an API, and show you not only how to use Debug Mode, but also how it works under the hood.
I am Yann Tavernier and I am a developer in the amazing APIM team. I had the opportunity to work on Debug Mode, and I’m delighted to walk you through and explain this feature!
Before we start looking at Debug Mode, let’s provide an overview of all of the key concepts and components that we’ll be using in this blog.
We are now going to introduce our simple scenario to walk through how to use Debug Mode.
All our examples will be done on a local installation. You can use this command to run APIM 3.17 with docker-compose
:
cd /tmp && mkdir -p apim && cd apim && curl -L https://raw.githubusercontent.com/gravitee-io/gravitee-docker/master/apim/3.x/docker-compose.yml -o "docker-compose.yml" && export APIM_VERSION=3.17.1 && docker-compose down -v && docker-compose pull && docker-compose up
To access the console, go to the following address: http://localhost:8084
.
The default credentials are:
admin
admin
If you are interested in a more detailed guide, you can check this awesome blog from Ljubica Lazarevic!
We will rely on an API called Library backend. You can import it thanks to its API definition here.
This backend will be accessible on http://localhost:8082/library-backend
and return mocked dataset:
{
"books": [
{
"title": "A tale of two cities",
"author": "Charles Dickens",
"_internalReference": "gio_b1"
},
{
"title": "The Lord of the Rings",
"author": "J.R.R Tolkien",
"_internalReference": "gio_b2"
},
{
"title": "The Hitchhiker's Guide to the Galaxy",
"author": "Douglas Adams",
"_internalReference": "gio_b3"
}
]
}
We will analyze this dataset later.
As an API Publisher, I want to design a “Library” API to access my Library backend.
You can create it following the documentation and follow this guide step by step or you can directly import the resulting API Definition.
First of all, I need to choose the type of plan to use for my API. We will choose two plans: a Keyless plan, called Free, and an API-Key one, called Premium.
Let’s firstly design the Free plan. This plan allows anybody to reach our APIs. To protect our backend systems, as well as improve performance, we want to manage the amount of traffic that will hit our API with this plan. We will limit the access thanks to the Rate Limit policy. One thing to note – as this is a free plan, consuming applications do not need to create a subscription.
As the API is going to be publicly accessible, we will want to hide away some private data in the response, the _internalReference
field. To do this, we’re going to use the JSON to JSON Transformation policy.
Here is the configuration of JSON To JSON Policy. Its purpose is to remove the _internalReference
field in the array of books
:
[
{
"operation": "remove",
"spec": {
"books": {
"*": {
"_internalReference": ""
}
}
}
}
]
Let’s deploy the API (you can do this by syncing the API when prompted) and call it with a cURL. Calling curl http://localhost:8082/library
will output:
{
"books": [
{
"title": "A tale of two cities",
"author": "Charles Dickens"
},
{
"title": "The Lord of the Rings",
"author": "J.R.R Tolkien"
},
{
"title": "The Hitchhiker's Guide to the Galaxy",
"author": "Douglas Adams"
}
]
}
Remember, the _internalReference
removal was done on the Freemium plan. Here, with the Internal plan, we keep the original data. We will use this opportunity to use the Assign Attributes policy to add an internal attribute in the context. This attribute will be the concatenation of the application’s ID followed by “-internal” and accessible through the “internal” key.
To do that, we configured the Assign Attribute policy to add an internal
attribute with the following value:
{#context.attributes["application"]}-internal
.
Now, calling the APIs with an API Key with curl http://localhost:8082/library?api-key=7cc755d1-378b-4099-9650-9ee9330be55c
will output:
{
"books": [
{
"title": "A tale of two cities",
"author": "Charles Dickens",
"_internalReference": "gio_b1"
},
{
"title": "The Lord of the Rings",
"author": "J.R.R Tolkien",
"_internalReference": "gio_b2"
},
{
"title": "The Hitchhiker's Guide to the Galaxy",
"author": "Douglas Adams",
"_internalReference": "gio_b3"
}
]
}
NOTE: You may have noticed that we cannot see the attribute we set. In fact, the attribute only lives inside the API Gateway for the time of the call. This is a behavior of the policy we are using, and it is internal to the gateway.
Finally, we will create a flow on the API using the JSON to JSON transformation again to apply discounts to a book based on certain conditions.
The discount will be applied if the response is either:
“X-Library-Discount”:”discount percentage”
.internal
is not empty.By default, the discount value will be the value of the X-Library-Discount
header, or 10 percent by default.
To achieve that, we will firstly configure the condition of the policy:
{(#request.headeers['X-Library-Discount'] != null && #request.headers['X-Library-Discount'].size() > 0) || {#context.attributes['internal'] != null}}
Then, we will use this configuration for JSON to JSON Policy:
[
{
"operation": "shift",
"spec": {
"*": "&"
}
},
{
"operation": "default",
"spec": {
"discount": "{#request.headers['X-Library-Discount'] != null ? #request.headers['X-Library-Discount'][0] : 10}%"
}
}
]
Calling the API with curl http://localhost:8082/library?api-key=7cc755d1-378b-4099-9650-9ee9330be55c
will output:
{
"message":"Request failed unintentionally",
"http_status_code":500
}
We have some issues with our last flow, but what happened? It’s hard to say by just using cURL or Postman. As the API design complexity increases, the risk of problems also increases. How can we avoid deploying our API to our users until we’ve solved all of the outstanding issues?
The APIM team created the new Debug Mode to solve this exact challenge.
The Debug Mode feature provides a way to have a global understanding and overview of what happens inside the gateway. With this feature, we are now able to send a request using our HTTP client, and see exactly which policies have been executed, with their inputs and outputs.
In the following screenshot, you can see an example of a request flow being examined using the Debug Mode:
The request is using the same API key as before, and we can see the Response ended in 500 — Internal Server Error
.
Let’s take a look at what the Debug Mode feature is showing us. The first important element of this feature is the timeline. It represents each policy that was run, shaped as a card. A card is composed of several elements:
It represents the real order of execution of your policies, which may have changed from your initial design. You may notice that the execution could be different from what you expected!
If you’re a regular user of Gravitee, you are probably used to configuring policies and choosing one of the following scopes: REQUEST
, REQUEST_CONTENT
, RESPONSE
, RESPONSE_CONTENT
. For REQUEST
and RESPONSE
scopes, policy execution has no view or modification access on the content, contrary to REQUEST_CONTENT
and RESPONSE_CONTENT
.
We will not deep dive into this topic, but an important thing to note is that the gateway will first execute the header policies (REQUEST
/ RESPONSE
) and then the content policies (REQUEST_CONTENT
/ RESPONSE_CONTENT
).
Let’s click on the card to explore what information it provides.
Thanks to this differential view (we will call it a “diff”), we now can see and understand how the Assign Attributes works: it adds an attribute in the Attribute object of the internal context of the call.
So now, why did our request fail? Let’s scroll the timeline and find the failing policy.
Here it is! We can see two icons appearing on our JSON to JSON Transformation card. Looking at the Inspector, we can see it occurring on Api > Body.
Looking at the diff, we can see the error message: “Request failed unintentionally”. This is what we saw and caught during the request processing. Unfortunately, in this case, it’s not very helpful.
The interesting thing, however, is the Condition block:
We can see that the condition is invalid. Reading the condition once more, it looks like we configured our policy using request.headeers
instead of request.headers
.
So how exactly does Debug Mode work? Let’s take a look under the hood.
When you send your Debug Request, the API Gateway detects the event, and it starts its processing.
It will deploy your current API in a particular state we call “Shadow Deployment”. This just means that the API is deployed, but not accessible to the public. This deployment is only used by Debug Mode, meaning there is no risk of your customers (or any other users!) accessing this version of your API!
You don’t need to deploy your API the regular way to be able to debug it. This can be really useful when you are doing some tests to find good tuning for a policy.
Let’s see it how it works:
As we said earlier, the condition was misspelled, so we have now fixed request.headeers
to request.headers
in the JSON To JSON policy.
Let’s do the call once again in debug mode:
The response is 200 — OK
, and we can see the discount applied in the response body.
Debug Mode can also tell us if a policy is not executing due to an unmet condition.
If we do not call the API with an api-key or X-Library-Discount
, this JSON to JSON policy will not be applied, as you can see in the timeline:
We’ve just done a simple example of a failing APIs with policy issues, and how to troubleshoot it with Debug Mode. We were able to see and step through the flows to understand what was really happening and what was causing the problem. Also, we have looked at how exactly Debug Mode works under the hood.
We would love to hear your feedback, and how you’re getting on with Debug Mode. If the topic interests you and you have questions, do not hesitate to join our community forum. The team will be happy to discuss it with you!
See you in a new article with all the info on this new MCQ season…
E-commerce's rapid expansion has changed how businesses function and how consumers shop, emphasizing the need…
In modern web development, scalability has become a key concern. As applications grow in complexity…
We meet again as usual for the start of the start of autumn season QCM…
The WeLoveDevs MCQs winter season came to an end on February 29th, and Manuvai Rehua…
There are several announcements today. The first is that it's the end of Winter and…