<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Apache APISIX</title>
    <description>The latest articles on DEV Community by Apache APISIX (@apisix).</description>
    <link>https://dev.to/apisix</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5306%2F37b37d97-8262-4047-884f-3fff61fbdf71.png</url>
      <title>DEV Community: Apache APISIX</title>
      <link>https://dev.to/apisix</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/apisix"/>
    <language>en</language>
    <item>
      <title>Release Apache APISIX Ingress Controller 2.0</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Mon, 22 Dec 2025 06:50:22 +0000</pubDate>
      <link>https://dev.to/apisix/release-apache-apisix-ingress-controller-20-346n</link>
      <guid>https://dev.to/apisix/release-apache-apisix-ingress-controller-20-346n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Apache APISIX Ingress Controller 2.0 is officially released. It delivers comprehensive Gateway API support, flexible multi-data-plane deployment, and etcd-free operation for robust, scalable Kubernetes traffic management.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Built on the high-performance API gateway Apache APISIX, &lt;a href="https://github.com/apache/apisix-ingress-controller" rel="noopener noreferrer"&gt;APISIX Ingress Controller&lt;/a&gt; has undergone multiple iterations and validations, and is now capable of handling large-scale traffic management demands. The Apache APISIX community is pleased to announce the official release of &lt;a href="https://apisix.apache.org/docs/ingress-controller/overview/" rel="noopener noreferrer"&gt;APISIX Ingress Controller 2.0&lt;/a&gt;. This release delivers substantial enhancements across three foundational pillars—&lt;strong&gt;comprehensive compatibility&lt;/strong&gt;, &lt;strong&gt;adaptable architecture&lt;/strong&gt;, and &lt;strong&gt;enterprise-grade stability&lt;/strong&gt;—empowering users to migrate their technology stacks smoothly and reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highlights of Apache APISIX Ingress Controller 2.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Support Gateway API
&lt;/h3&gt;

&lt;p&gt;This release achieves a significant milestone in Gateway API coverage with the addition of TCPRoute, UDPRoute, GRPCRoute, and TLSRoute. These extensions provide native, protocol-aware routing for a wide range of traffic types—from traditional HTTP and TCP/UDP to modern gRPC and TLS passthrough/termination. This unified support allows organizations to manage diverse ingress requirements within a consistent, future-ready configuration model, simplifying multi-protocol deployment and easing the transition to full Gateway API adoption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduce Gateway API Extensions
&lt;/h3&gt;

&lt;p&gt;Building upon adherence to the Gateway API design principles, APISIX Ingress Controller 2.0 introduces a set of API extensions under &lt;code&gt;apisix.apache.org/v1alpha1&lt;/code&gt; based on the Gateway API. These extensions provide additional capabilities not currently directly covered by the standard Gateway API, while maintaining the core semantics and usage patterns of the standard resources. They are designed to meet more complex and diverse real-world usage scenarios.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GatewayProxy&lt;/strong&gt;: It defines the connection between the APISIX Ingress Controller and the APISIX, including auth, endpoints, and global plugins. It is referenced via &lt;code&gt;parametersRef&lt;/code&gt; in Gateway, GatewayClass, or IngressClass resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BackendTrafficPolicy&lt;/strong&gt;: It is for fine-grained traffic management of backend services, including load balancing, timeouts, retries, and host header handling in the APISIX Ingress Controller.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consumer&lt;/strong&gt;: It defines API consumers and their credentials, enabling authentication and plugin configuration for controlling access to API endpoints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PluginConfig&lt;/strong&gt;: It defines reusable plugin configurations that can be referenced by other resources like HTTPRoute, enabling separation of routing logic and plugin settings for better reusability and manageability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTPRoutePolicy&lt;/strong&gt;: It configures advanced traffic management and routing policies for HTTPRoute or Ingress resources, enhancing functionality without modifying the original resources.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These extensions offer a standardized, vendor-supported path to leverage advanced APISIX features directly within the Gateway API ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support APISIX Standalone API-Driven Mode
&lt;/h3&gt;

&lt;p&gt;APISIX Ingress Controller 2.0 offers a lightweight, etcd-free deployment option through its Standalone &lt;a href="https://apisix.apache.org/docs/apisix/deployment-modes/#api-driven" rel="noopener noreferrer"&gt;API-Driven Mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This deployment paradigm stores routing configurations entirely in memory rather than in a configuration file. Updates are performed through a dedicated Standalone Admin API, which replaces the full configuration in a single operation and takes effect immediately via hot reloading, without requiring a restart.&lt;/p&gt;

&lt;p&gt;This mode is designed specifically for the APISIX Ingress Controller and is primarily intended for integration with &lt;a href="https://github.com/api7/adc" rel="noopener noreferrer"&gt;ADC (API Declarative CLI)&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support Multi-Data-Plane Deployment Mode
&lt;/h3&gt;

&lt;p&gt;This release introduces flexible deployment options supporting multiple data plane modes, enabling a single ingress controller to manage several independent APISIX instances. This approach is ideal for environments requiring strict isolation—such as multi-tenancy, staging vs. production, or region-based routing—while maintaining centralized control.&lt;/p&gt;

&lt;h4&gt;
  
  
  Admin API Mode
&lt;/h4&gt;

&lt;p&gt;In the traditional deployment approach, APISIX uses etcd as its configuration center, allowing administrators to dynamically manage routes, upstreams, and other resources through RESTful APIs. It supports distributed cluster deployments with real-time configuration synchronization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F12%2F19%2FlX98Vcaj_apisix-ingress-controller-2-admin-api-mode.webp" class="article-body-image-wrapper"&gt;&lt;img alt="APISIX Ingress Controller Admin API Mode" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F12%2F19%2FlX98Vcaj_apisix-ingress-controller-2-admin-api-mode.webp" width="800" height="948"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Standalone Mode
&lt;/h4&gt;

&lt;p&gt;APISIX can also run independently without relying on etcd, which is especially well‑suited for Kubernetes and single‑node deployments. It stores configurations in memory and manages them through the dedicated &lt;code&gt;/apisix/admin/configs&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;This mode is particularly suitable for Kubernetes environments and single-node deployments, where the API-driven memory management approach combines the convenience of traditional Admin API with the simplicity of Standalone mode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F12%2F19%2F8IxjQgCP_apisix-ingress-controller-2-standalone-mode.webp" class="article-body-image-wrapper"&gt;&lt;img alt="APISIX Ingress Controller Standalone Mode" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F12%2F19%2F8IxjQgCP_apisix-ingress-controller-2-standalone-mode.webp" width="800" height="866"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This multi-mode strategy empowers organizations to tailor their ingress architecture to diverse requirements without sacrificing manageability or control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Apache APISIX Ingress Controller 2.0 represents a significant evolution in Kubernetes ingress management, delivering a robust platform built for the complexity of modern, multi-protocol applications. By uniting comprehensive Gateway API support, extensible configuration through official API extensions, a lightweight standalone deployment mode, and versatile multi-data-plane management, this release provides a cohesive and powerful foundation for dynamic cloud environments.&lt;/p&gt;

&lt;p&gt;Whether you are standardizing ingress across diverse workloads, seeking greater architectural flexibility, or requiring enterprise-grade stability at scale, APISIX Ingress Controller 2.0 offers a forward-looking solution that simplifies operations without compromising capability. It stands as a testament to the community-driven innovation within the Apache APISIX ecosystem, designed to meet today's demands while adapting to tomorrow's challenges.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a complete list of features and changes, please refer to the &lt;a href="https://github.com/apache/apisix-ingress-controller/blob/2.0.0/CHANGELOG.md#200" rel="noopener noreferrer"&gt;Release Changelog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ingress</category>
      <category>api</category>
      <category>apigateway</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Load Balancing AI/ML API with Apache APISIX</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Thu, 31 Jul 2025 09:13:52 +0000</pubDate>
      <link>https://dev.to/apisix/load-balancing-aiml-api-with-apache-apisix-4d7e</link>
      <guid>https://dev.to/apisix/load-balancing-aiml-api-with-apache-apisix-4d7e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This blog provides a step-by-step guide to configure Apache APISIX for AI traffic splitting and load balancing between API versions, covering security setup, canary testing, and deployment monitoring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aimlapi.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;AI/ML API&lt;/strong&gt;&lt;/a&gt; is a one-stop, OpenAI-compatible endpoint that is trusted by 150,000+ developers to 300+ state-of-the-art models—chat, vision, image/video/music generation, embeddings, OCR, and more—from Google, Meta, OpenAI, Anthropic, Mistral, and others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/apache/apisix" rel="noopener noreferrer"&gt;&lt;strong&gt;Apache APISIX&lt;/strong&gt;&lt;/a&gt; is a dynamic, real-time, high-performance API Gateway. APISIX API Gateway provides rich traffic management features and can serve as an AI Gateway through its flexible plugin system.&lt;/p&gt;

&lt;p&gt;Modern AI workloads often require smooth version migrations, A/B testing, and rolling updates. This guide shows you how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt; Apache APISIX with Docker quickstart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure&lt;/strong&gt; the Admin API with keys and IP whitelisting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define&lt;/strong&gt; separate routes for API versions v1 and v2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement&lt;/strong&gt; weighted traffic splitting (50/50) via the &lt;code&gt;traffic-split&lt;/code&gt; plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; the newly created split endpoint functionality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load test&lt;/strong&gt; and &lt;strong&gt;monitor&lt;/strong&gt; distribution accuracy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To perform authenticated requests, you'll need an AI/ML API key. You can get one at &lt;a href="https://aimlapi.com/app/keys?utm_source=apisix&amp;amp;utm_medium=guide&amp;amp;utm_campaign=integration" rel="noopener noreferrer"&gt;https://aimlapi.com/app/keys/&lt;/a&gt; and use it as a Bearer token in your Authorization headers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea8t6m1725922ppm9moj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea8t6m1725922ppm9moj.webp" alt="Generate AI/ML API Key" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quickstart Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Download and run the quickstart script (includes etcd + APISIX)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://run.api7.ai/apisix/quickstart | sh

&lt;span class="c"&gt;# 2. Confirm APISIX is up and running&lt;/span&gt;
curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://127.0.0.1:9080 | &lt;span class="nb"&gt;grep &lt;/span&gt;Server
&lt;span class="c"&gt;# ➜ Server: APISIX/3.13.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you encounter port conflicts, adjust Docker host networking or map to different ports in the quickstart script.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Secure the Admin API
&lt;/h2&gt;

&lt;p&gt;By default, quickstart bypasses Admin API authentication. For any non-development environment, enforce security:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Set an Admin Key
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;conf/config.yaml&lt;/code&gt; inside the APISIX container or local install directory, replacing the example key with your own API key obtained from the link above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apisix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enable_admin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;            &lt;span class="c1"&gt;# Enable Admin API&lt;/span&gt;
  &lt;span class="na"&gt;admin_key_required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;      &lt;span class="c1"&gt;# Reject unauthenticated Admin requests&lt;/span&gt;
  &lt;span class="na"&gt;admin_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YOUR_ADMIN_KEY_HERE&lt;/span&gt;  &lt;span class="c1"&gt;# Generated admin key - you can replace this with a secure key as you wish&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Best Practice:&lt;/strong&gt; Use at least 32 characters, mix letters/numbers/symbols, and rotate keys quarterly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Whitelist Management IPs (allow_admin)
&lt;/h3&gt;

&lt;p&gt;Add your management or local networks under the &lt;code&gt;admin:&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;admin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allow_admin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;127.0.0.0/24&lt;/span&gt;   &lt;span class="c1"&gt;# Localhost &amp;amp; host network&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;      &lt;span class="c1"&gt;# Allow all (temporary/testing only)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; &lt;code&gt;0.0.0.0/0&lt;/code&gt; opens Admin API to the world! Lock this down to specific subnets in production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Restart APISIX
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker restart apisix-quickstart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Check Logs:&lt;/strong&gt; &lt;code&gt;docker logs apisix-quickstart --tail 50&lt;/code&gt; to ensure no errors about admin authentication.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Define Basic Routes for v1 and v2
&lt;/h2&gt;

&lt;p&gt;Before splitting traffic, ensure each version works individually.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Route for v1
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:9180/apisix/admin/routes/test-v1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-X&lt;/span&gt; PUT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-KEY: YOUR_ADMIN_KEY_HERE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "uri": "/test/v1",
    "upstream": {
      "type": "roundrobin",
      "nodes": {"api.aimlapi.com:443": 1},
      "scheme": "https",
      "pass_host": "node"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Use &lt;code&gt;id&lt;/code&gt; fields if you want to manage or delete routes easily later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Route for v2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:9180/apisix/admin/routes/test-v2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-X&lt;/span&gt; PUT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-KEY: YOUR_ADMIN_KEY_HERE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "uri": "/test/v2",
    "upstream": {
      "type": "roundrobin",
      "nodes": {"api.aimlapi.com:443": 1},
      "scheme": "https",
      "pass_host": "node"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implement Traffic Splitting (50/50)
&lt;/h2&gt;

&lt;p&gt;Use the &lt;a href="https://apisix.apache.org/docs/apisix/plugins/traffic-split/" rel="noopener noreferrer"&gt;&lt;code&gt;traffic-split&lt;/code&gt;&lt;/a&gt; plugin for controlled distribution between v1 and v2. In the admin request below, replace &lt;code&gt;YOUR_ADMIN_KEY_HERE&lt;/code&gt; with your actual key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:9180/apisix/admin/routes/aimlapi-split &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-X&lt;/span&gt; PUT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-KEY: YOUR_ADMIN_KEY_HERE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "id": "aimlapi-split",
    "uri": "/chat/completions",
    "upstream": {
      "type": "roundrobin",
      "nodes": {"api.aimlapi.com:443": 1},
      "scheme": "https",
      "pass_host": "node"
    },
    "plugins": {
      "traffic-split": {
        "rules": [
          {
            "weight": 50,
            "upstream": {"type":"roundrobin","nodes":{"api.aimlapi.com:443":1},"scheme":"https","pass_host":"node"},
            "rewrite": {"uri":"/v1/chat/completions"}
          },
          {
            "weight": 50,
            "upstream": {"type":"roundrobin","nodes":{"api.aimlapi.com:443":1},"scheme":"https","pass_host":"node"},
            "rewrite": {"uri":"/v2/chat/completions"}
          }
        ]
      }
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Adjust the &lt;code&gt;weight&lt;/code&gt; values to shift traffic ratios (e.g., 80/20 for canary).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;rewrite&lt;/code&gt; must match the internal API path exactly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Verify Split Endpoint Functionality
&lt;/h2&gt;

&lt;p&gt;Test the &lt;code&gt;/chat/completions&lt;/code&gt; endpoint you just created. Replace &lt;code&gt;&amp;lt;AIML_API_KEY&amp;gt;&lt;/code&gt; with the key obtained earlier and use it as a Bearer token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:9080/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;AIML_API_KEY&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model":"gpt-4","messages":[{"role":"user","content":"ping"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Pong! How can I assist you today?"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Use &lt;code&gt;-v&lt;/code&gt; for verbose output to troubleshoot headers or TLS issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Load Test &amp;amp; Distribution Validation
&lt;/h2&gt;

&lt;p&gt;After configuring the split route, use the following commands to validate distribution. Replace &lt;code&gt;&amp;lt;AIML_API_KEY&amp;gt;&lt;/code&gt; with your Bearer token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Send 100 test requests&lt;/span&gt;
&lt;span class="nb"&gt;time seq &lt;/span&gt;100 | xargs &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:9080/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;AIML_API_KEY&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model":"gpt-4","messages":[{"role":"user","content":"ping"}]}'&lt;/span&gt;
&lt;span class="c"&gt;# 2. Check APISIX logs for upstream hits (replace IPs with actual resolved IPs)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"v1 hits: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker logs apisix-quickstart &lt;span class="nt"&gt;--since&lt;/span&gt; 5m | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'188.114.97.3:443'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"v2 hits: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker logs apisix-quickstart &lt;span class="nt"&gt;--since&lt;/span&gt; 5m | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'188.114.96.3:443'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected:&lt;/strong&gt; Approximately 50 requests to each upstream.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Use Prometheus or OpenTelemetry plugins for real‑time metrics instead of manual log parsing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Best Practices &amp;amp; Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting &amp;amp; Quotas&lt;/strong&gt;: Add &lt;a href="https://apisix.apache.org/docs/apisix/plugins/limit-count/" rel="noopener noreferrer"&gt;&lt;code&gt;limit-count&lt;/code&gt;&lt;/a&gt; plugin to protect your upstream from spikes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: Layer on the &lt;a href="https://apisix.apache.org/docs/apisix/plugins/key-auth/" rel="noopener noreferrer"&gt;&lt;code&gt;key-auth&lt;/code&gt;&lt;/a&gt; plugin for consumer management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit Breaker&lt;/strong&gt;: Prevent cascading failures with the &lt;a href="https://apisix.apache.org/docs/apisix/plugins/api-breaker/" rel="noopener noreferrer"&gt;&lt;code&gt;api-breaker&lt;/code&gt;&lt;/a&gt; plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability&lt;/strong&gt;: Integrate Prometheus, Skywalking, or Loki for dashboards and alerts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code&lt;/strong&gt;: Consider managing APISIX config via Kubernetes CRDs or ADC for reproducibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/getting-started/load-balancing/" rel="noopener noreferrer"&gt;APISIX Load Balancing Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aimlapi.com/?utm_source=apisix&amp;amp;utm_medium=guide&amp;amp;utm_campaign=integration" rel="noopener noreferrer"&gt;AI/ML API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>aiops</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>Announcing APISIX Integration with AI/ML API</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Wed, 30 Jul 2025 08:56:39 +0000</pubDate>
      <link>https://dev.to/apisix/announcing-apisix-integration-with-aiml-api-20gm</link>
      <guid>https://dev.to/apisix/announcing-apisix-integration-with-aiml-api-20gm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;We're thrilled to announce that &lt;strong&gt;AI/ML API&lt;/strong&gt; has become a supported provider to the &lt;code&gt;ai-proxy&lt;/code&gt;, &lt;code&gt;ai-proxy-multi&lt;/code&gt;, and &lt;code&gt;ai-request-rewrite&lt;/code&gt; plugins in &lt;strong&gt;Apache APISIX&lt;/strong&gt;. All the AI/ML APIs will be supported in the next APISIX version.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aimlapi.com/" rel="noopener noreferrer"&gt;AI/ML API&lt;/a&gt; is a single endpoint that gives you access to more than 300 ready-to-use AI models—large language models, embeddings, image and audio tools—through one standard REST interface. It is used by over 150,000 developers and organizations as a centralized LLM API gateway.&lt;/p&gt;

&lt;p&gt;We're thrilled to announce that &lt;strong&gt;AI/ML API&lt;/strong&gt; has become a supported provider to the &lt;code&gt;ai-proxy&lt;/code&gt;, &lt;code&gt;ai-proxy-multi&lt;/code&gt;, and &lt;code&gt;ai-request-rewrite&lt;/code&gt; plugins in &lt;strong&gt;Apache APISIX&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AI/ML API provides a unified OpenAI-compatible API with access to &lt;strong&gt;300+ LLMs&lt;/strong&gt; such as GPT-4, Claude, Gemini, DeepSeek, and others. This integration bridges the gap between your API infrastructure and leading AI services, enabling you to deploy intelligent features—like chatbots, real-time translations, and data analysis—faster than ever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy to OpenAI via AI/ML API
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://apisix.apache.org/docs/apisix/installation-guide/" rel="noopener noreferrer"&gt;Install APISIX&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Generate your API key on &lt;a href="https://aimlapi.com/app/keys/" rel="noopener noreferrer"&gt;AI/ML API dashboard&lt;/a&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdreryvcnlz5evdzbi8r9.webp" alt="Generate AI/ML API Key" width="800" height="451"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Configure the Route
&lt;/h3&gt;

&lt;p&gt;Create a route and configure the &lt;code&gt;ai-proxy&lt;/code&gt; plugin as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \&lt;/span&gt;
  &lt;span class="s"&gt;-H "X-API-KEY&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${ADMIN_API_KEY}" \&lt;/span&gt;
  &lt;span class="s"&gt;-d '{&lt;/span&gt;
    &lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai-proxy-route"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uri"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/anything"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;methods"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plugins"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai-proxy"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aimlapi"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auth"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;header"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY"'"&lt;/span&gt; &lt;span class="c1"&gt;# Generated openai key from AI/ML API dashboard&lt;/span&gt;
          &lt;span class="pi"&gt;}&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options"&lt;/span&gt;&lt;span class="pi"&gt;:{&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4"&lt;/span&gt;
        &lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test the Integration
&lt;/h3&gt;

&lt;p&gt;Send a POST request to the route with a system prompt and a sample user question in the request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"http://127.0.0.1:9080/anything"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: api.openai.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "messages": [
      { "role": "system", "content": "You are a mathematician" },
      { "role": "user", "content": "What is 1+1?" }
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Response
&lt;/h3&gt;

&lt;p&gt;You should receive a response similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"choices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"finish_reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"logprobs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assistant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1 + 1 equals 2."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"refusal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"annotations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1753845968&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-4-0613"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"usage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prompt_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1449&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"completion_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2457&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Core Use Cases
&lt;/h2&gt;

&lt;p&gt;1.&lt;strong&gt;Unified AI Service Management&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Model Proxy and Load Balancing&lt;/strong&gt;: Replace hardcoded vendor endpoints with a single APISIX interface, dynamically routing requests to models from OpenAI, Claude, DeepSeek, Gemini, Mistral, etc., based on cost, latency, or performance needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendor-Agnostic Workflows&lt;/strong&gt;: Seamlessly switch between models (e.g., GPT-4 for creative tasks, Claude for document analysis) without code changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2.&lt;strong&gt;Cost-Optimized Token Governance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token-Based Budget Enforcement&lt;/strong&gt;: Set per-team/monthly spending limits; auto-throttle requests when thresholds are exceeded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching &amp;amp; Fallbacks&lt;/strong&gt;: Cache frequent LLM responses (e.g., FAQ answers) or reroute to cheaper models during provider outages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.&lt;strong&gt;Real-Time AI Application Scaling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chatbots &amp;amp; Virtual Agents&lt;/strong&gt;: Power low-latency conversational interfaces with streaming support for token-by-token responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Enrichment Pipelines&lt;/strong&gt;: Augment APIs with AI—e.g., auto-summarize user reviews or translate product descriptions on-the-fly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4.&lt;strong&gt;Hybrid/Multi-Cloud AI Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unified Control Plane&lt;/strong&gt;: Manage on-prem LLMs (e.g., Llama 3) alongside cloud APIs (OpenAI, Azure) with consistent policy enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Availability &amp;amp; Fault Tolerance&lt;/strong&gt;: Built-in health-checks, automatic retries and failover; if one LLM fails, traffic is rerouted within seconds to keep services alive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5.&lt;strong&gt;Enterprise AI Security &amp;amp; Compliance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Security and Compliance&lt;/strong&gt;: Prompt Guard, content moderation, PII redaction, and full audit logs in a single place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Auth Layer for 300+ LLMs&lt;/strong&gt;: Unified authentication (JWT/OAuth2/OIDC) and authorization for 300+ LLM keys and policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With AI/ML API now natively supported in Apache APISIX, you no longer have to choose between &lt;strong&gt;speed&lt;/strong&gt;, &lt;strong&gt;security&lt;/strong&gt;, or &lt;strong&gt;scale&lt;/strong&gt;—you get all three.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One line of YAML&lt;/strong&gt; turns your gateway into a 300-model AI powerhouse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero code changes&lt;/strong&gt; let you hot-swap GPT-4 for Claude, or route 10 % of traffic to a cheaper model for instant cost savings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in guardrails&lt;/strong&gt; (PII redaction, token budgets, content moderation) keep compliance teams happy while your product team ships faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  More Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Related APISIX AI Plugins

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/plugins/ai-proxy/" rel="noopener noreferrer"&gt;ai-proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/plugins/ai-proxy-multi/" rel="noopener noreferrer"&gt;ai-proxy-multi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/plugins/ai-request-rewrite/" rel="noopener noreferrer"&gt;ai-request-rewrite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://aimlapi.com/community" rel="noopener noreferrer"&gt;AI/ML API Community&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>apigateway</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>From stdio to HTTP SSE: Host Your MCP Server with APISIX API Gateway</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Mon, 21 Apr 2025 10:24:20 +0000</pubDate>
      <link>https://dev.to/apisix/from-stdio-to-http-sse-host-your-mcp-server-with-apisix-api-gateway-26i2</link>
      <guid>https://dev.to/apisix/from-stdio-to-http-sse-host-your-mcp-server-with-apisix-api-gateway-26i2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In contemporary API infrastructure, HTTP protocols and streaming communications (like SSE, WebSocket) have become mainstream for building real-time, interactive applications. Over the past few months, the Model Context Protocol (MCP) has gained popularity. However, most MCP Servers are implemented via stdio for local environments and cannot be invoked by external services and developers.&lt;/p&gt;

&lt;p&gt;To bridge these services with modern API architectures, Apache APISIX has introduced the &lt;code&gt;mcp-bridge&lt;/code&gt; plugin. It seamlessly converts stdio-based MCP services into HTTP SSE streaming interfaces and manages them through an API gateway for routing and traffic management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model Context Protocol (MCP) Overview
&lt;/h2&gt;

&lt;p&gt;MCP is an open protocol that standardizes how AI applications provide context information to large language models (LLMs). It allows developers to switch between different LLM providers while ensuring data security and facilitating integration with local or remote data sources. Supporting a client-server architecture, MCP servers expose specific functionalities that are accessible to clients via these servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the &lt;code&gt;mcp-bridge&lt;/code&gt; Plugin?
&lt;/h2&gt;

&lt;p&gt;The Apache APISIX &lt;code&gt;mcp-bridge&lt;/code&gt; plugin launches a subprocess to manage the MCP Server, takes over its stdio channel, transforms client HTTP SSE requests into MCP protocol calls, and pushes responses back to the client via SSE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📡 Wraps MCP RPC calls into SSE message streams&lt;/li&gt;
&lt;li&gt;🔄 Manages subprocess stdio lifecycle with queued RPC scheduling&lt;/li&gt;
&lt;li&gt;🗂️ Lightweight MCP session management (including session ID, ping keep-alive, and queuing)&lt;/li&gt;
&lt;li&gt;🧰 Supports session sharing across multiple workers for stability in APISIX multi-worker environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works and Architecture Diagram
&lt;/h2&gt;

&lt;p&gt;Below is a sequence diagram illustrating the working mechanism of the &lt;code&gt;mcp-bridge&lt;/code&gt; plugin, helping you to understand the data flow from stdio to SSE:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wbycka73jbv164hhxg6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wbycka73jbv164hhxg6.webp" alt="MCP-Bridge Architecture Diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Highlights:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APISIX manages SSE long-lived connections&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;mcp-bridge&lt;/code&gt; plugin handles subprocesses, stdio, and scheduling queues&lt;/li&gt;
&lt;li&gt;Clients receive real-time subprocess outputs, forming streaming SSE responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Application Scenarios and Benefits
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Typical Application Scenarios&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🛠️ Integrating existing MCP/stdio services with web platforms&lt;/li&gt;
&lt;li&gt;🖥️ Cross-language and cross-platform subprocess service management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅ Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Modernization: Instantly transform stdio services into HTTP SSE APIs&lt;/li&gt;
&lt;li&gt;🕹️ Managed: Unified management of subprocess launch and IO lifecycle&lt;/li&gt;
&lt;li&gt;📈 Scalability: Session sharing in multi-worker environments for large-scale deployment support&lt;/li&gt;
&lt;li&gt;🔄 Traffic Control Integration: Seamless API management system integration with APISIX traffic control, authentication, and rate-limiting plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Authentication and Rate Limiting with Apache APISIX Plugins
&lt;/h2&gt;

&lt;p&gt;Apache APISIX provides robust authentication plugins (like OAuth 2.0, JWT, and OIDC) and rate-limiting plugins (such as rate limiting and circuit breakers). These enhance the &lt;code&gt;mcp-bridge&lt;/code&gt; plugin, ensuring secure authentication and traffic control for connected MCP services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication Plugins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Support for OAuth 2.0, JWT, and OIDC plugins to protect APIs and MCP services.&lt;/li&gt;
&lt;li&gt;Automatic client identity verification during API gateway requests to prevent unauthorized access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rate-Limiting Plugins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rate Limiting: Restricts each client's request rate to prevent system overload.&lt;/li&gt;
&lt;li&gt;Circuit Breaker: Automatically switches or returns errors to avoid system crashes during high traffic or failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding Authentication and Rate Limiting to MCP Servers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqkpu6g204rzqlbcbmrp.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqkpu6g204rzqlbcbmrp.webp" alt="Add Authentication and Rate Limiting to MCP Servers" width="800" height="678"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By integrating authentication and rate-limiting plugins with the &lt;code&gt;mcp-bridge&lt;/code&gt; plugin, you can enhance API security and ensure system stability in high-concurrency environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;The current version is a prototype. Future enhancements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Currently, MCP sessions are not shared across multiple APISIX instances. For multi-node APISIX clusters, proper session persistence configuration on the front-end load balancer is essential to ensure requests from the same client always go to the same APISIX instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The current MCP SSE connection is loop-driven. While the loop doesn't consume many resources (stdio read/write will be synchronous non-blocking calls), it's not efficient. We plan to connect to a message queue for an event-driven, scalable cluster approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The MCP session management module is just a prototype. We intend to abstract an MCP proxy server module to support launching MCP servers within APISIX for advanced scenarios. This proxy server module will be event-driven rather than loop-driven.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The Apache APISIX &lt;code&gt;mcp-bridge&lt;/code&gt; plugin significantly simplifies the integration of Model Context Protocol (MCP) services with the HTTP API world. It offers a modern streaming interface management approach for traditional services.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aiops</category>
      <category>mcp</category>
      <category>api</category>
    </item>
    <item>
      <title>APISIX-MCP: Embracing Intelligent API Management with AI + MCP</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Wed, 02 Apr 2025 03:03:57 +0000</pubDate>
      <link>https://dev.to/apisix/apisix-mcp-embracing-intelligent-api-management-with-ai-mcp-38j8</link>
      <guid>https://dev.to/apisix/apisix-mcp-embracing-intelligent-api-management-with-ai-mcp-38j8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article introduces the MCP protocol and its application in APISIX-MCP. APISIX-MCP simplifies API management through natural language interaction, supporting the creation, updating, and deletion of resources.  &lt;/p&gt;


&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the explosive growth of large-scale AI model applications, many traditional systems are eager to integrate AI capabilities quickly. However, the current landscape of AI tools lacks unified standards, resulting in severe fragmentation. Different models vary in capability and integration methods, creating significant challenges for traditional applications during adoption.  &lt;/p&gt;

&lt;p&gt;Against this backdrop, in late 2024, Anthropic—the company behind the renowned Claude model—introduced the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;. MCP positions itself as the &lt;strong&gt;"USB-C interface" for AI applications&lt;/strong&gt;. Just as USB-C standardizes connections for peripherals and accessories, MCP provides a standardized approach for AI models to connect with diverse data sources and tools.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2Fu6Q4dGDZ_apisix-mcp-architecture-new.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2Fu6Q4dGDZ_apisix-mcp-architecture-new.webp" alt="MCP Architecture" width="800" height="524"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Numerous services and applications have already adopted MCP. For example:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub-MCP&lt;/strong&gt; enables natural language code submissions and PR creation.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Figma MCP&lt;/strong&gt; allows AI to generate UI designs directly.
&lt;/li&gt;
&lt;li&gt;With &lt;strong&gt;Browser-tools-MCP&lt;/strong&gt;, tools like Cursor can debug code by interacting with DOM elements and console logs.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official MCP repository includes implementations for Google Drive, Slack, Git, and various databases. As an open standard, MCP has gained widespread recognition in the AI community, attracting third-party developers who contribute hundreds of new MCP services daily. Anthropic, as the founder, actively drives MCP’s evolution by refining the protocol and educating developers.  &lt;/p&gt;

&lt;h2&gt;
  
  
  About APISIX-MCP
&lt;/h2&gt;

&lt;p&gt;The rise of MCP offers traditional applications a new technical pathway. Leveraging MCP’s standardized integration capabilities, we developed &lt;a href="https://github.com/api7/apisix-mcp" rel="noopener noreferrer"&gt;&lt;strong&gt;APISIX-MCP&lt;/strong&gt;&lt;/a&gt;, which bridges large language models with Apache APISIX’s Admin API through natural language interaction. The current implementation supports the following operations:  &lt;/p&gt;

&lt;h3&gt;
  
  
  General Operations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_resource&lt;/code&gt;: Retrieve resources by type (routes, services, upstreams, etc.).
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;delete_resource&lt;/code&gt;: Delete resources by ID.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Resource Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;create_route&lt;/code&gt;/&lt;code&gt;update_route&lt;/code&gt;/&lt;code&gt;delete_route&lt;/code&gt;: Manage routes.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_service&lt;/code&gt;/&lt;code&gt;update_service&lt;/code&gt;/&lt;code&gt;delete_service&lt;/code&gt;: Manage services.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_upstream&lt;/code&gt;/&lt;code&gt;update_upstream&lt;/code&gt;/&lt;code&gt;delete_upstream&lt;/code&gt;: Manage upstreams.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_ssl&lt;/code&gt;/&lt;code&gt;update_ssl&lt;/code&gt;/&lt;code&gt;delete_ssl&lt;/code&gt;: Manage SSL certificates.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_or_update_proto&lt;/code&gt;: Manage Protobuf definitions.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_or_update_stream_route&lt;/code&gt;: Manage stream routes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Plugin Operations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_all_plugin_names&lt;/code&gt;: List all available plugins.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_plugin_info&lt;/code&gt;/&lt;code&gt;get_plugins_by_type&lt;/code&gt;/&lt;code&gt;get_plugin_schema&lt;/code&gt;: Fetch plugin configurations.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_plugin_config&lt;/code&gt;/&lt;code&gt;update_plugin_config&lt;/code&gt;: Manage plugin configurations.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_global_rule&lt;/code&gt;/&lt;code&gt;update_global_rule&lt;/code&gt;: Manage global plugin rules.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_plugin_metadata&lt;/code&gt;/&lt;code&gt;create_or_update_plugin_metadata&lt;/code&gt;/&lt;code&gt;delete_plugin_metadata&lt;/code&gt;: Manage plugin metadata.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security Configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_secret_by_id&lt;/code&gt;/&lt;code&gt;create_secret&lt;/code&gt;/&lt;code&gt;update_secret&lt;/code&gt;: Manage secrets.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_or_update_consumer&lt;/code&gt;/&lt;code&gt;delete_consumer&lt;/code&gt;: Manage consumers.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_credential&lt;/code&gt;/&lt;code&gt;create_or_update_credential&lt;/code&gt;/&lt;code&gt;delete_credential&lt;/code&gt;: Manage consumer credentials.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_consumer_group&lt;/code&gt;/&lt;code&gt;delete_consumer_group&lt;/code&gt;: Manage consumer groups.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use APISIX-MCP
&lt;/h2&gt;

&lt;p&gt;APISIX-MCP is now open-sourced and available on &lt;a href="https://www.npmjs.com/package/apisix-mcp" rel="noopener noreferrer"&gt;npm&lt;/a&gt; and &lt;a href="https://github.com/api7/apisix-mcp" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. It can be configured via any MCP-compatible AI client, such as Claude Desktop, Cursor, or the Cline plugin for VSCode.  &lt;/p&gt;

&lt;p&gt;Below is a step-by-step guide using &lt;strong&gt;Cursor&lt;/strong&gt;:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Cursor, click the settings icon, and navigate to the settings page.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2FOCQcecuQ_apisix-mcp-2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2FOCQcecuQ_apisix-mcp-2.webp" alt="Configure cursor for APISIX-MCP" width="800" height="327"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;"Add new global MCP server"&lt;/strong&gt; to edit the &lt;code&gt;mcp.json&lt;/code&gt; configuration file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"apisix-mcp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apisix-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"APISIX_SERVER_HOST"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-apisix-server-host"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"APISIX_ADMIN_API_PORT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-apisix-admin-api-port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"APISIX_ADMIN_API_PREFIX"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-apisix-admin-api-prefix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"APISIX_ADMIN_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-apisix-api-key"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;mcpServers&lt;/code&gt; field of the configuration file, add a service &lt;code&gt;apisix-mcp&lt;/code&gt;, which can be changed. Then configure the commands for running the MCP service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;command&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;npx&lt;/code&gt; (Node.js package executor).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;args&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;-y&lt;/code&gt; (auto-install dependencies) and &lt;code&gt;apisix-mcp&lt;/code&gt; (package name).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;env&lt;/code&gt;&lt;/strong&gt;: Customize APISIX connection settings (defaults below):
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;env&lt;/code&gt; field, you can specify the APISIX service access address, Admin API port, prefix, and authentication key. These environment variables have default values, so if you start APISIX without any custom configuration, you can omit the &lt;code&gt;env&lt;/code&gt; field entirely. The default values for each variable are as follows:&lt;/p&gt;

&lt;p&gt;| Variable                  | Description                          | Default Value               |&lt;br&gt;&lt;br&gt;
   |---------------------------|--------------------------------------|-----------------------------|&lt;br&gt;&lt;br&gt;
   | &lt;code&gt;APISIX_SERVER_HOST&lt;/code&gt;      | APISIX server host                   | &lt;code&gt;http://127.0.0.1&lt;/code&gt;          |&lt;br&gt;&lt;br&gt;
   | &lt;code&gt;APISIX_ADMIN_API_PORT&lt;/code&gt;   | Admin API port                       | &lt;code&gt;9180&lt;/code&gt;                      |&lt;br&gt;&lt;br&gt;
   | &lt;code&gt;APISIX_ADMIN_API_PREFIX&lt;/code&gt; | Admin API prefix                     | &lt;code&gt;/apisix/admin&lt;/code&gt;             |&lt;br&gt;&lt;br&gt;
   | &lt;code&gt;APISIX_ADMIN_KEY&lt;/code&gt;        | Admin API authentication key         | &lt;code&gt;edd1c9f034335f136f87ad84b625c8f1&lt;/code&gt; |  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upon successful configuration, the MCP Servers list will show a green indicator for &lt;code&gt;apisix-mcp&lt;/code&gt;, along with available tools.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2FtoaXLc3n_apisix-mcp-3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2FtoaXLc3n_apisix-mcp-3.webp" alt="Successful Configuration" width="" height=""&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If setup fails, refer to the &lt;a href="https://github.com/api7/apisix-mcp" rel="noopener noreferrer"&gt;APISIX-MCP GitHub&lt;/a&gt; documentation for manual builds.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the chat panel, select &lt;strong&gt;Agent&lt;/strong&gt; mode and choose a model (e.g., Claude Sonnet 3.5/3.7 or GPT-4o).
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2Fg9v91DIf_apisix-mcp-4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.api7.ai%2Fuploads%2F2025%2F04%2F01%2Fg9v91DIf_apisix-mcp-4.webp" alt="Select Agent Models" width="800" height="139"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next, we can enter relevant operational commands to verify if the MCP service is functioning correctly. Following the workflow in APISIX's Getting Started documentation, we input the following into the dialog box and send the message:
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Help me create a route with path &lt;code&gt;/api&lt;/code&gt; for accessing &lt;code&gt;https://httpbin.org&lt;/code&gt; upstream, with CORS and rate-limiting plugins. Print the route details after configuration."&lt;/em&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next, in Cursor, you will see a process similar to the MCP tool invocation demonstrated in the video below. Due to the inherent randomness of large AI model responses, the exact operations performed may vary from the example shown.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
     &lt;br&gt;&lt;br&gt;
     &lt;/p&gt;

&lt;p&gt;Here, the auto-execution mode (YOLO Mode) is enabled, allowing Cursor to automatically invoke all tools in the MCP server. From the video, we can observe the AI performing the following operations based on our requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyzing the plugins we need to configure, then calling &lt;code&gt;get_plugins_list&lt;/code&gt; to retrieve all plugin names&lt;/li&gt;
&lt;li&gt;Invoking &lt;code&gt;get_plugin_schema&lt;/code&gt; to examine detailed configuration information for different plugins&lt;/li&gt;
&lt;li&gt;Calling &lt;code&gt;create_route&lt;/code&gt; to create the route&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;update_route&lt;/code&gt; to add the previously queried plugin configurations to the route&lt;/li&gt;
&lt;li&gt;Executing &lt;code&gt;get_route&lt;/code&gt; to verify whether the route was successfully configured and if the configuration is correct&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;The resulting route configuration includes:
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Route ID&lt;/strong&gt;: &lt;code&gt;httpbin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path&lt;/strong&gt;: &lt;code&gt;/api/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods&lt;/strong&gt;: &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, &lt;code&gt;HEAD&lt;/code&gt;, &lt;code&gt;OPTIONS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CORS Plugin&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;allow_origins: *
allow_methods: *
allow_headers: *
expose_headers: X-Custom-Header
max_age: 3600
allow_credential: false
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;limit-count Plugin&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;count: 100
time_window: 60
key: remote_addr
rejected_code: 429
policy: local
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Upstream&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type: roundrobin (load balancing strategy using round-robin)  
upstream node: httpbin.org:443 (backend service address)  
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages of AI-Driven Operations
&lt;/h2&gt;

&lt;p&gt;In the above process, we accomplished the creation of a route configured with CORS and rate-limiting through just one round of natural language interaction with AI. Compared to manual route configuration, leveraging AI offers several distinct advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Cognitive Load&lt;/strong&gt;: Eliminates manual documentation lookup and parameter memorization.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Workflows&lt;/strong&gt;: AI decomposes tasks (e.g., plugin setup → route creation) without human intervention.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closed-Loop Validation&lt;/strong&gt;: Auto-verification ensures correctness.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterative Optimization&lt;/strong&gt;: Continuous dialogue refines configurations.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This interaction model transforms complex configuration processes into natural conversational experiences while maintaining accuracy and verifiability. These capabilities are achieved through the MCP protocol's semantic parsing of requirements, intelligent tool invocation, and final execution via Admin API.&lt;/p&gt;

&lt;p&gt;It's important to note that APISIX-MCP isn't designed to completely replace manual configuration, but rather to optimize efficiency for high-frequency operations. Its value shines particularly in configuration debugging and rapid validation scenarios, creating effective complementarity with traditional management approaches. As the MCP ecosystem continues to evolve, we can anticipate deeper integration of such tools in API management, promising more sophisticated capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;MCP enables intelligent operations for complex API systems. APISIX-MCP lowers the barrier to Apache APISIX adoption, with future plans for AI-traffic-specific plugins. The fusion of AI and API management promises smarter, more efficient infrastructure governance. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>aiops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What Is an AI Gateway: Differences from API Gateway</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Fri, 28 Mar 2025 03:26:32 +0000</pubDate>
      <link>https://dev.to/apisix/what-is-an-ai-gateway-differences-from-api-gateway-1c63</link>
      <guid>https://dev.to/apisix/what-is-an-ai-gateway-differences-from-api-gateway-1c63</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"The future isn't AI gateways—it's API gateways that speak AI."_ This blog explores AI gateways, their differences from API gateways, and why evolved solutions like &lt;a href="https://apisix.apache.org/blog/2025/02/24/apisix-ai-gateway-features/" rel="noopener noreferrer"&gt;Apache APISIX AI Gateway&lt;/a&gt; are shaping the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is an AI Gateway? Why Did It Arise in the AI Era?
&lt;/h2&gt;

&lt;p&gt;The AI era has ushered in unprecedented complexity in deploying and managing artificial intelligence (AI) models. Organizations now juggle multiple models—from computer vision to large language models (LLMs)—across diverse environments (cloud, edge, hybrid). Traditional API gateways, designed for general-purpose data traffic, often fall short in addressing the unique challenges posed by AI workloads. This is where &lt;strong&gt;AI gateways&lt;/strong&gt; emerge as critical middleware, acting as a unified control plane for routing, securing, and optimizing AI workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rise of AI Gateways
&lt;/h2&gt;

&lt;p&gt;The proliferation of &lt;strong&gt;generative AI and LLMs (Large Language Models)&lt;/strong&gt; has introduced unique challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token Consumption&lt;/strong&gt;: LLMs process requests in tokens, requiring granular tracking for cost and performance optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stream-Type Requests&lt;/strong&gt;: AI agents often generate real-time, streaming responses (e.g., ChatGPT's incremental output), demanding low-latency handling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Integration&lt;/strong&gt;: AI systems increasingly rely on external data sources and APIs (e.g., retrieving live weather data or CRM records).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to a 2023 Gartner report, over 75% of enterprises now use AI models in production, driving demand for specialized infrastructure. Traditional API gateways, designed for RESTful APIs and static request-response cycles, struggle with these AI-specific demands. Enter the &lt;a href="https://apisix.apache.org/blog/2025/03/06/what-is-an-ai-gateway/" rel="noopener noreferrer"&gt;AI gateway&lt;/a&gt;—a purpose-built solution to manage AI-native traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Agents vs. Traditional Devices: Why Stream-Type Requests Demand Specialized Handling
&lt;/h2&gt;

&lt;p&gt;AI agents (e.g., chatbots, coding assistants) generate fundamentally different traffic patterns than traditional clients:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Traditional API Requests&lt;/th&gt;
&lt;th&gt;AI Agent Requests&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Request Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Synchronous (HTTP GET/POST)&lt;/td&gt;
&lt;td&gt;Asynchronous, streaming (SSE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Milliseconds&lt;/td&gt;
&lt;td&gt;Seconds-minutes (for chunks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Billing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per API call&lt;/td&gt;
&lt;td&gt;Per token or compute time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failure Modes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Timeouts, HTTP errors&lt;/td&gt;
&lt;td&gt;Partial completions, hallucinations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Stream-Type Challenge
&lt;/h3&gt;

&lt;p&gt;When an AI agent requests a poem generated by GPT-4, the response is streamed incrementally. Traditional API gateways, built for atomic requests, struggle with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partial Responses&lt;/strong&gt;: Aggregating chunks into a coherent audit log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Accounting&lt;/strong&gt;: Accurately counting tokens across streaming chunks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Observability&lt;/strong&gt;: Monitoring latency per token or detecting drift in response quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many purpose-built AI gateways lack distributed tracing, forcing engineers to cobble together metrics. In contrast, API gateways like &lt;a href="https://github.com/apache/apisix" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt; provide built-in integrations with Prometheus and Grafana, enabling token-level dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Types of AI Gateways: Purpose-Built vs. API Gateway Evolutions
&lt;/h2&gt;

&lt;p&gt;Today's AI gateways fall into two categories:&lt;/p&gt;

&lt;h3&gt;
  
  
  Specific Purpose-Built AI Gateways
&lt;/h3&gt;

&lt;p&gt;These are built from the ground up to address AI use cases. Startups like &lt;strong&gt;PromptLayer&lt;/strong&gt; and &lt;strong&gt;LangChain&lt;/strong&gt; offer solutions focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token-Based Rate Limiting&lt;/strong&gt;: Enforcing usage quotas based on tokens instead of API calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Engineering Tools&lt;/strong&gt;: Allowing developers to test and optimize prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Specific Analytics&lt;/strong&gt;: Tracking metrics like response hallucination rates or token costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: OpenAI's API uses token-based pricing ($0.06 per 1K tokens for GPT-4), requiring gateways to meter usage precisely. A dedicated AI gateway might integrate token counters directly into its throttling logic.&lt;/p&gt;

&lt;p&gt;However, these gateways often lack the &lt;strong&gt;observability&lt;/strong&gt; and &lt;strong&gt;scalability&lt;/strong&gt; of mature API management platforms. For instance, measuring token consumption across distributed microservices can lead to inaccuracies if the gateway lacks distributed tracing capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evolved AI Gateways from API Gateways
&lt;/h3&gt;

&lt;p&gt;Established API gateways like Kong, &lt;strong&gt;&lt;a href="https://apisix.apache.org/" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;&lt;/strong&gt;, and AWS API Gateway are adapting to AI workloads by adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streaming Support&lt;/strong&gt;: Handling Server-Sent Events (SSE) and WebSockets for real-time AI responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token-Aware Plugins&lt;/strong&gt;: Extending rate-limiting plugins to track tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Orchestration&lt;/strong&gt;: Managing multiple AI models (e.g., routing requests to cost-effective models like Mistral-7B for simple tasks).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mature API gateways leverage decades of experience in security (OAuth, JWT), scalability (load balancing), and monetization—features often missing in AI-first solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Evolved AI Gateways Are Winning Long-Term
&lt;/h2&gt;

&lt;p&gt;While purpose-built AI gateways excel in niche scenarios, evolved API gateways are becoming the default choice for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency&lt;/strong&gt;: Maintaining separate gateways for AI and non-AI traffic doubles operational overhead. Converged systems reduce costs by 30–50% (Gartner, 2023).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Enterprises can't predict which AI models will dominate. Platforms like Apache APISIX allow seamless integration of new LLMs without rearchitecting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future-Proofing&lt;/strong&gt;: As AI becomes embedded in all apps (e.g., AI-powered search in e-commerce), gateways must handle hybrid workloads.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Model Context Protocol (MCP): Bridging AI Assistants and External Tools
&lt;/h2&gt;

&lt;p&gt;To connect AI agents with external data and APIs, the &lt;strong&gt;&lt;a href="https://github.com/modelcontextprotocol" rel="noopener noreferrer"&gt;Model Context Protocol (MCP)&lt;/a&gt;&lt;/strong&gt; has emerged as a standardized framework. MCP defines how AI models request and consume external resources, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Sources&lt;/strong&gt;: SQL databases, vector stores (e.g., Pinecone).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs&lt;/strong&gt;: CRM systems, payment gateways.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Code interpreters, and image generators.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How MCP Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Context Injection&lt;/strong&gt;: An AI assistant sends a request with a context header specifying required tools (&lt;code&gt;MCP-Context: weather_api, crm&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gateway Routing&lt;/strong&gt;: The AI gateway validates permissions, injects API keys, and routes the request to relevant services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Synthesis&lt;/strong&gt;: The gateway aggregates API responses (e.g., weather data + CRM contacts) and feeds them back to the AI model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: A user asks, "Email our top client in NYC about today's weather." The AI gateway uses MCP to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch the top client from Salesforce.&lt;/li&gt;
&lt;li&gt;Retrieve NYC weather from OpenWeatherMap.&lt;/li&gt;
&lt;li&gt;Pass this context to GPT-4 to draft the email.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benefits of MCP
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Centralized policy enforcement (e.g., masking PII in CRM responses).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Control&lt;/strong&gt;: Caching frequent data requests (e.g., product catalogs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interoperability&lt;/strong&gt;: Standardizing AI-to-API communication across vendors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future of AI Gateways: Convergence with API Monetization
&lt;/h2&gt;

&lt;p&gt;As AI adoption matures, two trends will shape AI gateways:&lt;/p&gt;

&lt;h3&gt;
  
  
  Trend 1: The Decline of Standalone AI Gateways
&lt;/h3&gt;

&lt;p&gt;Niche AI gateways will struggle to compete with evolved API gateways that offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unified Governance&lt;/strong&gt;: One platform for REST, GraphQL, and AI APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monetization Models&lt;/strong&gt;: Token-based billing, subscription tiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Features&lt;/strong&gt;: Role-based access control (RBAC), audit logging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under such a trend, AI traffic will flow through traditional API gateways enhanced with AI capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trend 2: API Gateways as AI Orchestrators
&lt;/h3&gt;

&lt;p&gt;Future API gateways will act as AI orchestrators, handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model Routing&lt;/strong&gt;: Directing requests to optimal models based on cost, latency, or accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Workflows&lt;/strong&gt;: Blending AI and non-AI services (e.g., validating a GPT-4 response against a database).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Analytics&lt;/strong&gt;: Real-time dashboards showing token spend by team or project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Bottom Line
&lt;/h3&gt;

&lt;p&gt;In the future, the line between "AI gateway" and "API gateway" will blur. But the unchangeable fact is APIs are the basics of API gateways and AI gateways. Companies that adopt AI-ready API gateways today will gain a strategic edge in scalability, cost control, and innovation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Embracing AI-API Convergence
&lt;/h2&gt;

&lt;p&gt;AI gateways are not a replacement but an evolution of API gateways. While purpose-built solutions address immediate LLM challenges, their limitations in observability and scalability make them transitional. Established API gateways—enhanced with streaming support, token-aware plugins, and MCP—are poised to dominate.&lt;/p&gt;

&lt;p&gt;Solutions like &lt;strong&gt;&lt;a href="https://apisix.apache.org/blog/2025/02/24/apisix-ai-gateway-features/" rel="noopener noreferrer"&gt;Apache APISIX AI Gateway&lt;/a&gt;&lt;/strong&gt; exemplify this shift, blending AI-native features with battle-tested API management. As AI permeates every app, enterprises must choose platforms that scale beyond siloed use cases. The winners? Adaptable, extensible tools that speak both API and AI.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>apigateway</category>
      <category>openai</category>
    </item>
    <item>
      <title>Comprehensive Overview of APISIX AI Gateway Features</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Mon, 24 Feb 2025 07:46:15 +0000</pubDate>
      <link>https://dev.to/apisix/comprehensive-overview-of-apisix-ai-gateway-features-2m8j</link>
      <guid>https://dev.to/apisix/comprehensive-overview-of-apisix-ai-gateway-features-2m8j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article will provide an in-depth look at the AI gateway features of the current and upcoming versions of APISIX. As a multifunctional API and AI gateway, Apache APISIX offers efficient and secure LLM API calls for AI applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction: The Rise of AI Agents and the Evolution of AI Gateway
&lt;/h2&gt;

&lt;p&gt;In recent years, AI agents such as AutoGPT, Chatbots, and AI Assistants have seen rapid development. These applications rely heavily on API calls to large language models (LLMs), which has brought about challenges considering high concurrency, cost control, and security.&lt;/p&gt;

&lt;p&gt;Traditional API gateways primarily serve Web APIs and microservices and are not optimized for the unique needs of AI applications. This has led to the emergence of the concept of AI gateway. An AI gateway needs to provide enhanced capabilities in the following areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-LLM Proxy&lt;/strong&gt;: Support for multiple LLM providers to avoid vendor lock-in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Rate Limiting&lt;/strong&gt;: Prevent API abuse and optimize cost management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Protection&lt;/strong&gt;: Including prompt filtering and content moderation to ensure compliance of AI applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Traffic Management&lt;/strong&gt;: Dynamically adjust LLM weights based on cost, latency, and stability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apache APISIX is not only an API gateway but also an AI gateway through its plugins, helping AI applications call LLM APIs more efficiently and securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM Proxy: Efficient Management of Multiple LLM Backends
&lt;/h2&gt;

&lt;p&gt;AI applications typically do not rely on a single LLM provider but need to dynamically select the best model based on requirements. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using OpenAI GPT-4 for general text generation and Claude for legal document processing.&lt;/li&gt;
&lt;li&gt;Switching between Mistral and Gemini to optimize cost and throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Apache APISIX's LLM Proxy offers the following capabilities:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Support for Multiple LLM Providers: Including OpenAI, DeepSeek, Claude, Mistral, Gemini, etc., to avoid vendor lock-in.&lt;/p&gt;

&lt;p&gt;✅ LLM Weight and Priority Management: Adjust traffic distribution based on business needs.&lt;/p&gt;

&lt;p&gt;✅ Multi-LLM Load Balancing: Dynamically adjust LLM weights based on latency, cost, and stability.&lt;/p&gt;

&lt;p&gt;✅ Retry and Fallback Mechanisms: Ensure business continuity if an LLM API fails.&lt;/p&gt;

&lt;p&gt;✅ Load Balancing Across Different Providers of the Same LLM:&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Privately deployed DeepSeek.&lt;/li&gt;
&lt;li&gt;Official DeepSeek API.&lt;/li&gt;
&lt;li&gt;DeepSeek API from Volcano Engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users can flexibly allocate traffic weights among different DeepSeek providers based on latency, stability, and price to achieve the best calling strategy.&lt;/p&gt;

&lt;p&gt;These capabilities enable AI applications to adapt flexibly to different LLMs, improve reliability, and reduce API calling costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Security Protection: Ensuring Safe and Compliant Use of AI
&lt;/h2&gt;

&lt;p&gt;AI APIs may involve sensitive data, misleading information, and potential misuse. Therefore, an AI gateway needs to provide security at multiple levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI security capabilities provided by Apache APISIX include:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;AI RAG (Retrieval-Augmented Generation)&lt;/strong&gt;: Supports enterprise-owned knowledge bases to reduce LLM hallucinations and improve output reliability.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Prompt Guard&lt;/strong&gt;: Automatically intercepts sensitive, illegal, and inappropriate prompts to prevent malicious use by users.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Prompt Decorator&lt;/strong&gt;: Automatically adds content before and after user input to enhance the quality of LLM-generated content.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Prompt Template&lt;/strong&gt;: Makes it easier for users to reuse standardized prompts and improve interaction experience.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Response Filtering &amp;amp; Moderation&lt;/strong&gt;: Intercepts sensitive or non-compliant AI-generated content.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Logging &amp;amp; Auditing&lt;/strong&gt;: Provides complete API request logs for compliance audits.&lt;/p&gt;

&lt;p&gt;These security measures ensure that AI applications meet enterprise-level security requirements and avoid compliance risks due to misleading AI content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token Observability and Management: Preventing High Bills Due to API Abuse
&lt;/h2&gt;

&lt;p&gt;Calling LLM APIs consumes tokens, and API abuse can lead to significant costs. Apache APISIX provides fine-grained token monitoring and management mechanisms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The token management capabilities of Apache APISIX include:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Token Rate Limiting by Route/Service/Consumer/Consumer Group/Custom Dimension&lt;/p&gt;

&lt;p&gt;✅ Support for Multiple Rate Limiting Modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-machine vs. cluster rate limiting to accommodate different scales of AI API services.&lt;/li&gt;
&lt;li&gt;Fixed time window vs. sliding time window to flexibly control API rates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Different Rate Limiting Policies for Different LLMs: Prevent cost overruns.&lt;/p&gt;

&lt;p&gt;Through Apache APISIX, enterprises can achieve fine-grained management of token resources and prevent high bills due to API abuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Routing: Dynamic Traffic Management for AI APIs
&lt;/h2&gt;

&lt;p&gt;During AI API calls, different tasks may require different LLMs. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code generation requests → sent to GPT-4 or DeepSeek.&lt;/li&gt;
&lt;li&gt;Long-form summarization tasks → sent to Claude.&lt;/li&gt;
&lt;li&gt;General conversations → sent to GPT-3.5 or Gemini.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The smart routing capabilities of Apache APISIX include:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Context-Aware Routing Based on Request Content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the optimal LLM based on prompt type.&lt;/li&gt;
&lt;li&gt;Allocate different models (GPT-4 Turbo vs. GPT-3.5) based on user level (paid vs. free users).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Response Caching: Reduce redundant API calls and improve response speed.&lt;/p&gt;

&lt;p&gt;These capabilities help AI APIs run more efficiently, reduce API latency, and increase throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the rapid development of AI technology, API gateways also need to evolve to meet the unique needs of AI applications. Apache APISIX, with its LLM Proxy, token rate limiting, security protection, and smart routing features, has become the best choice for an AI gateway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The core advantages of Apache APISIX compared to traditional API gateways are:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🚀 Support for Multiple LLM Providers: Avoid vendor lock-in.&lt;/p&gt;

&lt;p&gt;⚡️ Smart Traffic Scheduling: Dynamic load balancing to improve API reliability.&lt;/p&gt;

&lt;p&gt;🔒 Built-in Security Capabilities: Including prompt protection and content moderation to ensure secure and compliant AI APIs.&lt;/p&gt;

&lt;p&gt;💰 Token Rate Limiting: Prevent high bills due to API abuse.&lt;/p&gt;

&lt;p&gt;📊 High-performance Architecture: Meet the high concurrency needs of AI applications.&lt;/p&gt;

&lt;p&gt;If you are building AI-related applications and want to have both a powerful API gateway and AI gateway, give Apache APISIX a try!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cloud vs Open Source vs Commercial API Gateways: Which One Fits Your Needs?</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Mon, 17 Feb 2025 09:39:13 +0000</pubDate>
      <link>https://dev.to/apisix/cloud-vs-open-source-vs-commercial-api-gateways-which-one-fits-your-needs-ecm</link>
      <guid>https://dev.to/apisix/cloud-vs-open-source-vs-commercial-api-gateways-which-one-fits-your-needs-ecm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;API gateways have become essential components in modern cloud architectures. They provide security, traffic management, observability, and service orchestration—critical for handling APIs at scale. However, with multiple API gateway solutions available, choosing the right one can be challenging.&lt;/p&gt;

&lt;p&gt;Broadly, API gateways fall into three categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud API Gateways&lt;/strong&gt; (e.g., &lt;a href="https://aws.amazon.com/api-gateway/" rel="nofollow noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;, &lt;a href="https://cloud.google.com/apigee" rel="nofollow noopener noreferrer"&gt;Google Apigee&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source API Gateways&lt;/strong&gt; (e.g., &lt;a href="https://apisix.apache.org/" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;, Kong Gateway, Tyk)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commercial API Gateways&lt;/strong&gt; (e.g., &lt;a href="https://www.mulesoft.com/" rel="nofollow noopener noreferrer"&gt;MuleSoft&lt;/a&gt;, &lt;a href="https://boomi.com/" rel="nofollow noopener noreferrer"&gt;Boomi&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each option has its advantages and trade-offs. This article provides a deep dive into their differences, hidden risks, and a &lt;strong&gt;strategic recommendation&lt;/strong&gt; for companies looking to scale API usage and adopt hybrid cloud architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud API Gateways: Convenience vs. Lock-in
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;p&gt;✅ Fully managed, reducing operational burden&lt;/p&gt;

&lt;p&gt;✅ Deep integration with cloud provider services (IAM, logging, monitoring)&lt;/p&gt;

&lt;p&gt;✅ High availability and auto-scaling out of the box&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Vendor Lock-in&lt;/strong&gt;: API definitions, policies, and configurations are tied to the cloud provider&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;No Customization&lt;/strong&gt;: Cloud API gateways are closed-source, limiting the ability to add custom plugins or functionality&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;No Hybrid Cloud Support&lt;/strong&gt;: Cloud-managed API gateways cannot be deployed on-premise or across multi-cloud environments&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case:
&lt;/h3&gt;

&lt;p&gt;Cloud API gateways are ideal for &lt;strong&gt;startups and small teams&lt;/strong&gt; that need a quick, managed solution without worrying about infrastructure maintenance. However, as API traffic grows or hybrid cloud requirements arise, their limitations become apparent.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Example&lt;/strong&gt;: Amazon API Gateway is a popular choice for cloud-native applications but lacks flexibility for on-premises deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source API Gateways: Control and Flexibility
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;p&gt;✅ Fully customizable, allowing teams to extend functionality as needed&lt;/p&gt;

&lt;p&gt;✅ No licensing fees, reducing costs in the long run&lt;/p&gt;

&lt;p&gt;✅ Can be deployed anywhere—&lt;strong&gt;on-prem, multi-cloud, hybrid cloud&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Operational Overhead&lt;/strong&gt;: Requires self-hosting, upgrades, and security management&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Governance Risks&lt;/strong&gt;: Some open-source projects are controlled by a single vendor, which may later change licensing terms (e.g., Redis, ELK Stack)&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Scalability Complexity&lt;/strong&gt;: Running an open-source API gateway at enterprise scale requires expertise in deployment and maintenance&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Consideration: Choosing a Foundation-Owned Open Source Project
&lt;/h2&gt;

&lt;p&gt;Some open-source API gateways are &lt;strong&gt;vendor-controlled&lt;/strong&gt;, meaning the company behind them can change licensing terms. For example, Redis and Elasticsearch modified their open-source licenses to prevent cloud providers from offering managed services.&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;avoid future licensing risks&lt;/strong&gt;, it's safer to choose an API gateway governed by a &lt;strong&gt;neutral open-source foundation&lt;/strong&gt;, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/" rel="noopener noreferrer"&gt;Apache APISIX (Apache Software Foundation)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.envoyproxy.io/" rel="nofollow noopener noreferrer"&gt;Envoy Proxy (Cloud Native Computing Foundation)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Commercial API Gateways: Enterprise Features with Pricing Risks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;Enterprise-grade security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;SLA-backed support&lt;/strong&gt; with 24/7 assistance&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Monetization and API analytics&lt;/strong&gt; for businesses offering APIs as a service&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;High Licensing Costs&lt;/strong&gt;: Typically charged per API call, which can become expensive&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Potential Pricing Changes&lt;/strong&gt;: Many vendors modify pricing models over time, significantly increasing costs (e.g., Apigee, Kong Enterprise)&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Limited Deployment Flexibility&lt;/strong&gt;: Some solutions require vendor-managed infrastructure, reducing control&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case:
&lt;/h3&gt;

&lt;p&gt;Best suited for &lt;strong&gt;large enterprises&lt;/strong&gt; with strict security, compliance, and SLA requirements. However, pricing unpredictability is a concern—many companies have faced sudden cost increases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategic Recommendation: A Hybrid Approach for Growth
&lt;/h2&gt;

&lt;p&gt;If your API traffic is &lt;strong&gt;growing rapidly&lt;/strong&gt; and &lt;strong&gt;hybrid cloud&lt;/strong&gt; is part of your strategy, the best approach is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Start with an Open Source API Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid vendor lock-in&lt;/li&gt;
&lt;li&gt;Maintain control over deployment and customization&lt;/li&gt;
&lt;li&gt;Lower costs by eliminating per-call fees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Upgrade to a Commercial Version When Needed&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When security requirements increase&lt;/li&gt;
&lt;li&gt;When managing multi-cluster deployments&lt;/li&gt;
&lt;li&gt;When enterprise support and SLAs become necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following this approach, you get the best of both worlds: flexibility, cost control, and enterprise-grade features when needed.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Example Strategy&lt;/strong&gt;: A company starts with Apache APISIX (open source) and later upgrades to &lt;a href="https://api7.ai/" rel="noopener noreferrer"&gt;API7 Enterprise&lt;/a&gt; when requiring advanced security and SLA support.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Common Questions About API Gateway Selection
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Why not start with a cloud API gateway and switch later?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switching API gateways is complex due to differences in configurations, rate-limiting rules, authentication methods, and monitoring setups. If hybrid cloud or multi-cloud is part of your strategy, starting with an open-source gateway ensures long-term flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. How do I avoid open-source licensing risks?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Choose projects governed by neutral software foundations (e.g., Apache Software Foundation, CNCF). Avoid projects fully controlled by a single company, as they may change their licensing model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What is the best API gateway for hybrid cloud?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open-source gateways like Apache APISIX and Envoy Proxy offer full deployment flexibility, making them ideal for hybrid and multi-cloud architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Making the Right Choice
&lt;/h2&gt;

&lt;p&gt;Choosing the right API gateway depends on your &lt;strong&gt;scalability, budget, and cloud strategy&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Cloud API Gateway&lt;/th&gt;
&lt;th&gt;Open Source API Gateway&lt;/th&gt;
&lt;th&gt;Commercial API Gateway&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (Pay per API call)&lt;/td&gt;
&lt;td&gt;Low (Free)&lt;/td&gt;
&lt;td&gt;High (License fees)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Full control&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud-only&lt;/td&gt;
&lt;td&gt;Anywhere (Hybrid, Multi-cloud)&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enterprise Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Requires customization&lt;/td&gt;
&lt;td&gt;Advanced (Security, Compliance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud provider support&lt;/td&gt;
&lt;td&gt;Community-driven&lt;/td&gt;
&lt;td&gt;SLA-backed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If &lt;strong&gt;API traffic is growing rapidly&lt;/strong&gt; and &lt;strong&gt;hybrid cloud adoption is planned&lt;/strong&gt;, a &lt;strong&gt;hybrid approach&lt;/strong&gt;—starting with &lt;strong&gt;open source&lt;/strong&gt; and upgrading to a &lt;strong&gt;commercial enterprise solution&lt;/strong&gt; when needed—offers the best flexibility and cost efficiency.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>api</category>
      <category>opensource</category>
      <category>compa</category>
    </item>
    <item>
      <title>Announcing Integration between Apache APISIX and open-appsec WAF</title>
      <dc:creator>Yilia</dc:creator>
      <pubDate>Wed, 23 Oct 2024 02:56:13 +0000</pubDate>
      <link>https://dev.to/apisix/announcing-integration-between-apache-apisix-and-open-appsec-waf-2jf9</link>
      <guid>https://dev.to/apisix/announcing-integration-between-apache-apisix-and-open-appsec-waf-2jf9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;open-appsec WAF is excited to announce a new integration with the open-source API gateway Apache APISIX.&lt;/p&gt;

&lt;p&gt;This new collaboration between the open-appsec and API7 teams now allows users to protect their web APIs and other web services exposed by Apache APISIX against unknown and known attack types effectively based on open-appsec's advanced machine-learning-based technology and also adds several more enhanced security capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  About Apache APISIX
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://apisix.apache.org/" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt; is a modern, flexible, and high-performance open-source API gateway solution designed to handle various use cases in microservices and cloud-native architectures. Its primary purpose is to facilitate API management by serving as a gateway for managing, securing, and optimizing API traffic between clients and backend services.&lt;/p&gt;

&lt;p&gt;Further use cases for APISIX as an API gateway include load balancing, rate limiting, authentication, and authorization. It provides comprehensive features such as traffic control, dynamic upstream, and plugin extensibility, enabling developers to customize and extend functionality according to their specific needs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Website: &lt;a href="https://apisix.apache.org" rel="noopener noreferrer"&gt;apisix.apache.org&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Github: &lt;a href="https://github.com/apache/apisix" rel="noopener noreferrer"&gt;github.com/apache/apisix&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docs: &lt;a href="https://apisix.apache.org/docs" rel="noopener noreferrer"&gt;apisix.apache.org/docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  About open-appsec WAF
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.openappsec.io" rel="noopener noreferrer"&gt;open-appsec WAF&lt;/a&gt; provides automatic, preemptive threat prevention and integrates with various types of reverse proxies like NGINX as well as API gateways like APISIX. It is machine-learning-based, meaning it doesn't require signatures (or updates) at all. This enables it to provide automatic, state-of-the-art threat prevention even for true zero-day attacks while significantly reducing both administrative effort and the amount of false positives.&lt;/p&gt;

&lt;p&gt;In addition, open-appsec provides many additional security layers such as AntiBot, rate limiting, schema enforcement, snort signature support, custom rules/exceptions, and more. open-appsec can be managed centrally using a Web UI provided as a SaaS service and also locally using a declarative configuration file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Website: &lt;a href="https://www.openappsec.io" rel="noopener noreferrer"&gt;www.openappsec.io&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Github: &lt;a href="https://github.com/openappsec" rel="noopener noreferrer"&gt;github.com/openappsec&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docs: &lt;a href="https://docs.openappsec.io" rel="noopener noreferrer"&gt;docs.openappsec.io&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Playgrounds: &lt;a href="https://www.openappsec.io/playground" rel="noopener noreferrer"&gt;www.openappsec.io/playground&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Integrating Apache APISIX with open-appsec
&lt;/h2&gt;

&lt;p&gt;With this new integration, APISIX users will now have access to open-appsec WAF as an integrated, state-of-the-art machine-learning-based WAF solution for the protection of their web APIs and web applications.&lt;/p&gt;

&lt;p&gt;They can now use e.g. open-appsec's free and open-source "Community Edition" to get effective, AI-based protection against known but also unknown attacks for everything exposed by their APISIX API gateway, while at the same time reducing the amount of false positives significantly unburdening the administrator from tedious tasks such as creating exceptions, updating traditional signature-based policies and more.&lt;/p&gt;

&lt;p&gt;This integration will be available for all common platforms: Linux, Docker, and Kubernetes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;For Linux "embedded" deployments&lt;/strong&gt; of APISIX, an open-appsec installer will add an "open-appsec attachment" module to the existing APISIX installation and also install the "open-appsec agent" alongside it, which will receive the traffic from the attachment, inspect it, and return the concluded action to block or allow the traffic back to the APISIX respectively the open-appsec attachment integrated with it.&lt;/p&gt;

&lt;p&gt;Here's a simple architecture schematic for Linux deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.apiseven.com%2Fuploads%2F2024%2F10%2F18%2F6QZvRy6P_linux-deployment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.apiseven.com%2Fuploads%2F2024%2F10%2F18%2F6QZvRy6P_linux-deployment.png" alt="Architecture for Linus Deployment" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;For Docker-based deployments&lt;/strong&gt; of APISIX with open-appsec WAF, there is a special APISIX container image available, to which the open-appsec attachment was already added and also an enhanced docker-compose file, which deploys both, the APISIX gateway container as well as an open-appsec Agent that does the security inspection and returns the concluded decisions to the APISIX gateway to allow or block traffic.&lt;/p&gt;

&lt;p&gt;Here's a simple architecture schematic for deployment on Docker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.apiseven.com%2Fuploads%2F2024%2F10%2F18%2FbxKsXOqW_docker-deployment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.apiseven.com%2Fuploads%2F2024%2F10%2F18%2FbxKsXOqW_docker-deployment.png" alt="Architecture for Docker-Based Deployment" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;For Kubernetes based-deployments&lt;/strong&gt; of APISIX integrated with open-appsec, there's a Helm chart available, which is based on the official APISIX Helm chart and further enhanced to also include the open-appsec attachment in the APISIX gateway container and also deploys the open-appsec agent. Further, you will have the option to configure open-appsec in a declarative "DevOps-style" way using custom resources in K8s as an alternative to using the open-appsec central management Web UI.&lt;/p&gt;

&lt;p&gt;Here's a simple architecture schematic for deployment on Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.apiseven.com%2Fuploads%2F2024%2F10%2F18%2FSEZQ6E14_k8s-deployment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.apiseven.com%2Fuploads%2F2024%2F10%2F18%2FSEZQ6E14_k8s-deployment.png" alt="Architecture for Kubernetes Deployment" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding open-appsec WAF to APISIX on Linux
&lt;/h2&gt;

&lt;p&gt;To install open-appsec on a Linux system with APISIX installed, please follow these steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Linux platform must be Ubuntu 22.04.&lt;/li&gt;
&lt;li&gt;Make sure to have APISIX installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the list of supported APISIX versions here: &lt;a href="https://downloads.openappsec.io/packages/supported-apisix.txt" rel="noopener noreferrer"&gt;https://downloads.openappsec.io/packages/supported-apisix.txt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don't have APISIX installed yet, you can use the following commands to perform an APISIX installation in "traditional mode". By running these commands you will first install the etcd database for APISIX, then add the required repos before installing and starting APISIX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install etcd Database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;ETCD_VERSION='&lt;/span&gt;&lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://github.com/etcd-io/etcd/releases/download/v$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;ETCD_VERSION&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;/etcd-v$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;ETCD_VERSION&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;-linux-amd&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="err"&gt;.tar.gz&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;tar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-xvf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etcd-v$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;ETCD_VERSION&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;-linux-amd&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="err"&gt;.tar.gz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etcd-v$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;ETCD_VERSION&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;-linux-amd&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etcd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etcdctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/usr/bin/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;nohup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etcd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;gt;/tmp/etcd.log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;etcd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add and Update Package Repositories&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gnupg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deb http://openresty.org/package/debian bullseye openresty"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/etc/apt/sources.list.d/openresty.list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-O&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://openresty.org/package/pubkey.gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apt-key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-O&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://repos.apiseven.com/pubkey.gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apt-key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deb http://repos.apiseven.com/packages/debian bullseye main"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/etc/apt/sources.list.d/apisix.list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;update&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Install, Initiate, and Start APISIX&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apisix=&lt;/span&gt;&lt;span class="mf"&gt;3.9&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1-0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;apisix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;init&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;apisix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;start&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Download the open-appsec Installer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://downloads.openappsec.io/open-appsec-install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;chmod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;open-appsec-install&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Install open-appsec
&lt;/h3&gt;

&lt;p&gt;Install open-appsec to integrate with the existing APISIX installation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the &lt;code&gt;--prevent&lt;/code&gt; flag will install open-appsec with a default policy already set to prevent mode.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./open-appsec-install &lt;span class="nt"&gt;--auto&lt;/span&gt; &lt;span class="nt"&gt;--prevent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Get and Store APISIX Admin Key
&lt;/h3&gt;

&lt;p&gt;Get the APISIX admin key from the APISIX &lt;code&gt;config.yaml&lt;/code&gt; configuration file and store it in the &lt;code&gt;APISIX_KEY&lt;/code&gt; env variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APISIX_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'/key:/{ if ($2 ~ /^edd1/) print $2 }'&lt;/span&gt; /usr/local/apisix/conf/config.yaml &lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Configure Route to Expose Services
&lt;/h3&gt;

&lt;p&gt;Configure an example route in the APISIX gateway to expose an external web service or web API. In this example, we use &lt;code&gt;httpbin.org&lt;/code&gt; as the example backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9180&lt;/span&gt;&lt;span class="err"&gt;/apisix/admin/routes/&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"X-API-KEY:$APISIX_KEY"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"methods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/anything"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"upstream"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"roundrobin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"httpbin.org:80"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Validate
&lt;/h3&gt;

&lt;p&gt;Let's see if this route works by accessing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-G&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--data-urlencode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email=user@domain.abc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;9080&lt;/span&gt;&lt;span class="err"&gt;/anything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Simulate an SQL Injection Attack
&lt;/h3&gt;

&lt;p&gt;Now let's try to simulate an SQL injection attack (see &lt;code&gt;'OR '1'='1'&lt;/code&gt; in the below HTTP request) against the &lt;code&gt;httpbin.org&lt;/code&gt; service exposed by the APISIX gateway which is now protected by the open-appsec WAF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-G&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--data-urlencode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email=user@domain.abc'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;'='&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;9080&lt;/span&gt;&lt;span class="err"&gt;/anything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simulated attack now gets blocked successfully by open-appsec's contextual machine-learning WAF engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Review Log Files
&lt;/h3&gt;

&lt;p&gt;Check out the corresponding log files showing the "prevent" for the HTTP request with the simulated attack that we just sent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/log/nano_agent/cp-nano-http-transaction-handler.log&lt;span class="k"&gt;*&lt;/span&gt;| &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; user@domain.abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively you can use the &lt;code&gt;open-appsec-ctl&lt;/code&gt; tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open-appsec-ctl &lt;span class="nt"&gt;--view-logs&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; user@domain.abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Connect to open-appsec for Central Management (Optional)
&lt;/h3&gt;

&lt;p&gt;Optionally you can connect your deployment now to &lt;a href="https://my.openappsec.io" rel="noopener noreferrer"&gt;https://my.openappsec.io&lt;/a&gt; for centrally managing open-appsec with an easy-to-use Web UI, monitoring security events and more, see section &lt;strong&gt;How to Manage Your open-appsec WAF Deployment Centrally?&lt;/strong&gt; further below for more information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt; You successfully added open-appsec WAF to your existing APISIX installation and verified that your web services exposed by the APISIX gateway are now protected against web attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying APISIX with open-appsec WAF on Containerized Platforms (Docker)
&lt;/h2&gt;

&lt;p&gt;To install APISIX integrated with open-appsec on Docker, you can follow the steps shown below.&lt;/p&gt;

&lt;p&gt;Opposite to the above example here we are deploying APISIX in "standalone mode", which means it's declaratively configured using a docker volume mount with a yaml file that holds the configurations and therefore won't require an etcd database deployment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that APISIX supports both, traditional as well as standalone modes in all deployment types (Linux, Docker, …)&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Prerequisite
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;Make sure to have a Linux platform with both Docker and docker-compose tools installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a Folder for open-appsec
&lt;/h3&gt;

&lt;p&gt;Within the directory that you want to use for the deployment, create a folder &lt;code&gt;appsec-localconfig&lt;/code&gt; which will hold the appsec declarative configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./appsec-localconfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Download the open-appsec File into the Folder
&lt;/h3&gt;

&lt;p&gt;Download the initial declarative configuration file for open-appsec into that folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://raw.githubusercontent.com/openappsec/openappsec/main/config/linux/latest/prevent/local_policy.yaml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-O&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;appsec-localconfig/local_policy.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that this example declarative configuration file is already set to prevent attacks.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Create a Folder for APISIX
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create another folder &lt;code&gt;apisix-localconfig&lt;/code&gt; which will hold the declarative configuration file for APISIX: &lt;code&gt;mkdir ./apisix-localconfig&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Download APISIX File into the Folder
&lt;/h3&gt;

&lt;p&gt;Let's download a simple declarative configuration file also for APISIX so we can verify open-appsec protection after the deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://raw.githubusercontent.com/openappsec/openappsec/main/deployment/apisix/apisix-example-config/apisix-standalone.yaml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-O&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./apisix-localconfig/apisix-standalone.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Create a &lt;code&gt;docer-compose.yaml&lt;/code&gt; File
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;docker-compose.yaml&lt;/code&gt; file with the content below, which can be downloaded as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://raw.githubusercontent.com/openappsec/openappsec/main/deployment/apisix/docker-compose.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;version:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;services:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;apisix:&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;container_name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apisix&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;image:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ghcr.io/openappsec/apisix-attachment:latest"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;ipc:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;service:appsec-agent&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;restart:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;volumes:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./apisix-localconfig/apisix-standalone.yaml:/usr/local/apisix/conf/apisix.yaml:ro&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;environment:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;APISIX_STAND_ALONE=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;ports:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9180:9180/tcp"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9080:9080/tcp"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9091:9091/tcp"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9443:9443/tcp"&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;appsec-agent:&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;container_name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;appsec-agent&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;image:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ghcr.io/openappsec/agent:latest'&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;ipc:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;shareable&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;restart:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;environment:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;adjust&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;own&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;below&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;user_email=user@email.com&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;registered_server=&lt;/span&gt;&lt;span class="s2"&gt;"APISIX Server"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;volumes:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./appsec-config:/etc/cp/conf&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./appsec-data:/etc/cp/data&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./appsec-logs:/var/log/nano_agent&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./appsec-localconfig:/ext/appsec&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;command:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/cp-nano-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Update Your Email Address (Optional)
&lt;/h3&gt;

&lt;p&gt;Edit the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file and replace "&lt;a href="mailto:user@email.com"&gt;user@email.com&lt;/a&gt;" with your own email address, so we can provide assistance in case of any issues with the specific deployment in the future and provide information proactively regarding open-appsec.&lt;/p&gt;

&lt;p&gt;This is an optional parameter and can be removed. If we send automatic emails, there will also be an opt-out option included for receiving similar communication in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Start All Containers
&lt;/h3&gt;

&lt;p&gt;Run docker-compose up to start the deployment of all relevant containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Check Container Status
&lt;/h3&gt;

&lt;p&gt;Check if the &lt;code&gt;apisix-attachment&lt;/code&gt; and the &lt;code&gt;appsec-agent&lt;/code&gt; containers are up and running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10. Validate the Standalone Configuration
&lt;/h3&gt;

&lt;p&gt;Let's see if the standalone configuration works by accessing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-G&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--data-urlencode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email=user@domain.abc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;9080&lt;/span&gt;&lt;span class="err"&gt;/anything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  11. Simulate an SQL Injection Attack
&lt;/h3&gt;

&lt;p&gt;Now let's try to simulate an SQL injection attack against the httpin.org service exposed by the APISIX gateway container which is now protected by open-appsec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-G&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--data-urlencode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email=user@domain.abc'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;'='&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;9080&lt;/span&gt;&lt;span class="err"&gt;/anything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  12. Connect to open-appsec for Central Management (Optional)
&lt;/h3&gt;

&lt;p&gt;Optionally you can connect your deployment now to &lt;code&gt;https://my.openappsec.io&lt;/code&gt; for centrally managing open-appsec with an easy-to-use Web UI, monitoring security events, and more, see section &lt;strong&gt;How to Manage Your open-appsec WAF Deployment Centrally?&lt;/strong&gt; further below for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying APISIX with open-appsec WAF on Kubernetes Using Helm
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Prerequisite
&lt;/h3&gt;

&lt;p&gt;Make sure the Kubernetes platform and Helm tool are available.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Download open-appsec
&lt;/h3&gt;

&lt;p&gt;Download the open-appsec for the APISIX Helm chart here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://downloads.openappsec.io/packages/helm-charts/apisix/open-appsec-k&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;s-apisix-latest.tgz&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Install Helm Chart
&lt;/h3&gt;

&lt;p&gt;This example &lt;code&gt;helm install&lt;/code&gt; command is installing the open-appsec for the APISIX Helm chart which is based on an extended version of the official APISIX Helm chart.&lt;/p&gt;

&lt;p&gt;It will deploy the APISIX gateway as the APISIX Ingress Controller, as well as open-appsec WAF integrated with it. It also offers an additional configuration option specifically for open-appsec WAF (see &lt;code&gt;values.yaml&lt;/code&gt; inside the Helm chart and open-appsec &lt;a href="https://docs.openappsec.io/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;After deployment, you can assign your K8s ingress resources to the APISIX gateway by configuring them to use the following ingress class: &lt;code&gt;appsec-apisix&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;open-appsec-k8s-apisix-latest.tgz &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name-template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;appsec-apisix &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; rbac.create&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; appsec.mode&lt;span class="o"&gt;=&lt;/span&gt;standalone &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; service.type&lt;span class="o"&gt;=&lt;/span&gt;LoadBalancer &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; appsec.persistence.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; ingress-controller.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; ingress-controller.config.ingressClass&lt;span class="o"&gt;=&lt;/span&gt;appsec-apisix &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; appsec.userEmail&lt;span class="o"&gt;=&lt;/span&gt;”&amp;lt;your-email-address&amp;gt;” &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; appsec.agentToken&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; appsec-apisix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Replace  in the Helm install command above with your own email address, so we can send you news and updates related to open-appsec and better support you with your deployment if needed! You can unsubscribe at any time or alternatively, just remove that line if you prefer not to provide your email.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Validate
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;Validate that pods were properly deployed and are in a ready state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; appsec-apisix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Create an open-appsec Policy Resource
&lt;/h3&gt;

&lt;p&gt;Run the following command to create the "open-appsec-best-practice-policy" in K8s.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that this example policy is already pre-configured to prevent attacks.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;kubectl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://raw.githubusercontent.com/openappsec/openappsec/main/config/k&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;s/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;beta&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/open-appsec-k&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;s-prevent-config-v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;beta&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create your own custom policy, &lt;a href="https://docs.openappsec.io/getting-started/start-with-kubernetes/configuration-using-crds" rel="noopener noreferrer"&gt;here&lt;/a&gt; you find all the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Fetch the Target Resource Name
&lt;/h3&gt;

&lt;p&gt;Find out the name of the relevant ingress resource which you want to protect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ing &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Edit the Ingress Resource
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl edit ing/&amp;lt;ingress name&amp;gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;ingress namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Change the ingressClassname
&lt;/h3&gt;

&lt;p&gt;Change the ingressClassname to use open-appsec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spec: ingressClassName: appsec-apisix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Add Annotation to the Ingress Resource
&lt;/h3&gt;

&lt;p&gt;Add this annotation to the ingress resource to activate open-appsec for this ingress by specifying the desired open-appsec policy custom resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openappsec.io/policy: open-appsec-best-practice-policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10. Validate the Standalone Configuration
&lt;/h3&gt;

&lt;p&gt;Let's see if the standalone configuration works by accessing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-G&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--data-urlencode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email=user@domain.abc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;YOUR-INGRESS-HOSTNAME&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  11. Simulate an SQL Injection Attack
&lt;/h3&gt;

&lt;p&gt;Now let's try to simulate an SQL injection attack against the &lt;code&gt;httpin.org&lt;/code&gt; service exposed by the APISIX gateway container which is now protected by open-appsec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-G&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--data-urlencode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;email=user@domain.abc'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;'='&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;YOUR-INGRESS-HOSTNAME&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace [YOUR-INGRESS-HOSTNAME] in the command above with the hostname you set in the ingress resource which you protected with open-appsec WAF in the earlier steps, also change "http" to "https" if required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt; You successfully deployed APISIX integrated with open-appsec WAF and verified that your web services exposed by the APISIX Gateway are now protected against attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Manage Your open-appsec WAF Deployment Centrally?
&lt;/h2&gt;

&lt;p&gt;If you like you can also manage your open-appsec WAF deployment (integrated with APISIX) centrally using the open-appsec Web UI (SaaS Service) available at &lt;a href="https://my.openappsec.io" rel="noopener noreferrer"&gt;https://my.openappsec.io&lt;/a&gt;, by connecting the open-appsec agent to a deployment profile in the central Web UI.&lt;/p&gt;

&lt;p&gt;You can alternatively continue to manage your deployment locally but still connect to a central WebUI profile in "Declarative mode" so that you will be able to see the local configuration (read-only) in the Web UI.&lt;/p&gt;

&lt;p&gt;Alongside the configuration of open-appsec the Web UI allows you to also see much more information like the status of deployed open-appsec agents, security logs, dashboards and more.&lt;/p&gt;

&lt;p&gt;For instructions on how to connect your deployment to the central Web UI see the open-appsec docs available at &lt;a href="https://docs.openappsec.io" rel="noopener noreferrer"&gt;https://docs.openappsec.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below you find some screenshots of the Web UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqeebb7dda7gnqnm8szn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqeebb7dda7gnqnm8szn.jpeg" alt="Open-websec UI 1" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flej53hpfuua1tfohl7nt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flej53hpfuua1tfohl7nt.jpeg" alt="Open-websec UI 2" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this blog we explained how open-appsec can integrate with Apache APISIX on all of the following: regular Linux-based deployments, containerized deployments (Docker), and also Kubernetes environments.&lt;/p&gt;

&lt;p&gt;Following the deployment steps for APISIX with open-appsec WAF, we simulated SQL injection attacks, which were effectively prevented by open-appsec's machine learning-based WAF technology.&lt;/p&gt;

&lt;p&gt;Additionally, it was explained, what the benefits are of connecting to open-appsec central WebUI for managing, monitoring, log analysis, and reporting.&lt;/p&gt;

&lt;p&gt;We hope these new integrations will prove very useful to enhance the security of your APISIX API gateway and its exposed web APIs and web applications with open-appsec machine learning-based WAF.&lt;/p&gt;

&lt;p&gt;Welcome you to contact us if you have any feedback, or questions or might face some technical challenge that you want us to assist with. You can reach the open-appsec team via the chat on &lt;a href="https://www.openappsec.io" rel="noopener noreferrer"&gt;https://www.openappsec.io&lt;/a&gt; or via email to: &lt;a href="//info@openappsec.io"&gt;info@openappsec.io&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  open-appsec WAF
&lt;/h3&gt;

&lt;p&gt;Website: &lt;a href="https://www.openappsec.io" rel="noopener noreferrer"&gt;https://www.openappsec.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/openappsec" rel="noopener noreferrer"&gt;https://github.com/openappsec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://docs.openappsec.io" rel="noopener noreferrer"&gt;https://docs.openappsec.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Playgrounds: &lt;a href="https://www.openappsec.io/playground" rel="noopener noreferrer"&gt;https://www.openappsec.io/playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blogs: &lt;a href="https://www.openappsec.io/blogs" rel="noopener noreferrer"&gt;https://www.openappsec.io/blogs&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Apache APISIX
&lt;/h3&gt;

&lt;p&gt;Website: &lt;a href="https://apisix.apache.org" rel="noopener noreferrer"&gt;https://apisix.apache.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/apache/apisix" rel="noopener noreferrer"&gt;https://github.com/apache/apisix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://apisix.apache.org/docs/" rel="noopener noreferrer"&gt;https://apisix.apache.org/docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blogs: &lt;a href="https://apisix.apache.org/blog/" rel="noopener noreferrer"&gt;https://apisix.apache.org/blog/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>DRY your Apache APISIX config</title>
      <dc:creator>Nicolas Fränkel</dc:creator>
      <pubDate>Thu, 05 Sep 2024 09:02:00 +0000</pubDate>
      <link>https://dev.to/apisix/dry-your-apache-apisix-config-85f</link>
      <guid>https://dev.to/apisix/dry-your-apache-apisix-config-85f</guid>
      <description>&lt;p&gt;DRY is an important principle in software development. This post will show you how to apply it to Apache APISIX configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DRY principle
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Don't repeat yourself" (DRY) is a principle of software development aimed at reducing repetition of information which is likely to change, replacing it with abstractions that are less likely to change, or using data normalization which avoids redundancy in the first place. &lt;/p&gt;

&lt;p&gt;-- &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;Wikipedia - Don't repeat yourself&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main idea behind DRY is that if you repeat yourself and the information changes, then you must update the changed information in multiple places. It's not only extra effort; there's a chance you'll forget about it and have different information in different places. DRY shines in bug fixing.&lt;/p&gt;

&lt;p&gt;Imagine a code snippet containing a bug. Imagine now that you have duplicated the snippet in two different places. Now, you must fix the bug in these two places, and that's the easy part; the hard being to know about the duplication in the first place. There's a high chance that the person duplicating and the one fixing are different. If the snippet had been refactored to be shareable and called from the two places instead, you only need to fix the bug in this one place.&lt;/p&gt;

&lt;p&gt;Most people associate DRY with code. However, it could be more limiting and contrary to the original idea.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The principle has been formulated by Andy Hunt and Dave Thomas in their book The Pragmatic Programmer. They apply it quite broadly to include database schemas, test plans, the build system, even documentation.&lt;/p&gt;

&lt;p&gt;-- &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;Wikipedia - Don't repeat yourself&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sound configuration systems allow DRY or even encourage it.&lt;/p&gt;

&lt;h2&gt;
  
  
  DRY in Apache APISIX
&lt;/h2&gt;

&lt;p&gt;Apache APISIX offers DRY configuration in two places.&lt;/p&gt;

&lt;h3&gt;
  
  
  DRY upstreams
&lt;/h3&gt;

&lt;p&gt;In an e-commerce context, your beginner journey to define a route on Apache APISIX probably starts like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Catalog&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;catalog:8080"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're familiar with APISIX, we defined a route to the catalogue under the &lt;code&gt;/products&lt;/code&gt; URI. However, there's an issue: you probably want would-be customers to browse the catalogue but want to prevent people from creating, deleting, or updating products. Yet, the route matches every HTTP method by default.&lt;/p&gt;

&lt;p&gt;We should allow only authenticated users to manage the catalogue so everybody can freely browse it. To implement this approach, we need to split the route in two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HEAD"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;                         &lt;span class="c1"&gt;#1&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                          &lt;span class="c1"&gt;#2&lt;/span&gt;
      &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;catalog:8080"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATCH"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;      &lt;span class="c1"&gt;#3&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/products*&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key-auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~&lt;/span&gt;                                      &lt;span class="c1"&gt;#4&lt;/span&gt;
    &lt;span class="na"&gt;upstream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                          &lt;span class="c1"&gt;#2&lt;/span&gt;
      &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;catalog:8080"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Match browsing&lt;/li&gt;
&lt;li&gt;Duplicated upstream!&lt;/li&gt;
&lt;li&gt;Match managing&lt;/li&gt;
&lt;li&gt;Only authenticated consumers can use this route; &lt;code&gt;key-auth&lt;/code&gt; is the simplest plugin for this&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We fixed the security issue in the simplest way possible: by copy-pasting. By doing so, we duplicated the &lt;code&gt;upstream&lt;/code&gt; section. If we need to change the topology, &lt;em&gt;e.g.&lt;/em&gt;, by adding or removing nodes, we must do it in two places. It defeats the DRY principle.&lt;/p&gt;

&lt;p&gt;In real-world scenarios, especially when they involve containers, you wouldn't implement the &lt;code&gt;upstream&lt;/code&gt; by listing &lt;code&gt;nodes&lt;/code&gt;. You should instead implement a dynamic &lt;a href="https://apisix.apache.org/docs/apisix/discovery/" rel="noopener noreferrer"&gt;service discovery&lt;/a&gt; to accommodate topology changes. However, the point still stands when you need to change the service discovery configuration or implementation. Hence, my point applies equally to nodes and service discovery.&lt;/p&gt;

&lt;p&gt;Along with the &lt;em&gt;Route&lt;/em&gt; abstraction, APISIX offers an &lt;em&gt;Upstream&lt;/em&gt; abstraction to implement DRY. We can rewrite the above snippet like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;upstreams&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;                                              &lt;span class="c1"&gt;#1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Catalog&lt;/span&gt;
    &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;catalog:8080"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HEAD"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;                                     &lt;span class="c1"&gt;#2&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATCH"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;                                     &lt;span class="c1"&gt;#2&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key-auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Define an upstream with ID &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reference it in the route&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If anything happens in the topology, we must update the change only in the single &lt;em&gt;Upstream&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note that defining the &lt;code&gt;upstream&lt;/code&gt; embedded and referencing it with &lt;code&gt;upstream_id&lt;/code&gt; are &lt;strong&gt;mutually exclusive&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  DRY plugin configuration
&lt;/h3&gt;

&lt;p&gt;Another area where APISIX can help you DRY your configuration with the &lt;em&gt;Plugin&lt;/em&gt; abstraction. APISIX implements most features, if not all, through plugins&lt;/p&gt;

&lt;p&gt;Let's implement &lt;a href="https://blog.frankel.ch/api-versioning/#path-based-versioning" rel="noopener noreferrer"&gt;path-based versioning&lt;/a&gt; on our API. We need to rewrite the URL before we forward it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HEAD"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/v1/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;proxy-rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;regex_uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1(.*)"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$1"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;                 &lt;span class="c1"&gt;#1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATCH"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/v1/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;proxy-rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;regex_uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1(.*)"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$1"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;                 &lt;span class="c1"&gt;#1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Remove the &lt;code&gt;/v1&lt;/code&gt; prefix before forwarding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Like with &lt;code&gt;upstream&lt;/code&gt; above, the &lt;code&gt;plugins&lt;/code&gt; section is duplicated. We can also factor the plugin configuration in a dedicated &lt;em&gt;Plugin Config&lt;/em&gt; object. The following snippet has the same effect as the one above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;plugin_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;                                              &lt;span class="c1"&gt;#1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;proxy-rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;regex_uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1(.*)"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$1"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HEAD"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/v1/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugin_config_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;                                &lt;span class="c1"&gt;#2&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATCH"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/v1/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugin_config_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;                                &lt;span class="c1"&gt;#2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Factor the plugin configuration in a dedicated object&lt;/li&gt;
&lt;li&gt;Reference it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Astute readers might have noticed that I'm missing part of the configuration: the &lt;code&gt;auth-key&lt;/code&gt; mysteriously disappeared! Indeed, I removed it for the sake of clarity.&lt;/p&gt;

&lt;p&gt;Unlike &lt;code&gt;upstream&lt;/code&gt; and &lt;code&gt;upstream_id&lt;/code&gt;, &lt;code&gt;plugins&lt;/code&gt; and &lt;code&gt;plugin_config_id&lt;/code&gt; are &lt;strong&gt;not mutually exclusive&lt;/strong&gt;. We can fix the issue by just adding the missing &lt;code&gt;plugin&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HEAD"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/v1/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugin_config_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the catalogue&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATCH"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/v1/products*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugin_config_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key-auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~&lt;/span&gt;                                      &lt;span class="c1"&gt;#1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Fix it!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This way, you can move the shared configuration to a &lt;code&gt;plugin_config&lt;/code&gt; object and keep a specific one to the place it applies to. But what if the same plugin with different configurations is used in the &lt;code&gt;plugin_config&lt;/code&gt; and directly in the &lt;code&gt;route&lt;/code&gt;? The &lt;a href="https://apisix.apache.org/docs/apisix/terminology/plugin/#plugins-merging-precedence" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; is pretty clear about it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Consumer&lt;/code&gt; &amp;gt; &lt;code&gt;Consumer Group&lt;/code&gt; &amp;gt; &lt;code&gt;Route&lt;/code&gt; &amp;gt; &lt;code&gt;Plugin Config&lt;/code&gt; &amp;gt; &lt;code&gt;Service&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short, the &lt;code&gt;plugin&lt;/code&gt; configuration in a &lt;code&gt;route&lt;/code&gt; overrules the configuration in the &lt;code&gt;plugin_config_id&lt;/code&gt;. It also allows us to provide the &lt;code&gt;apikey&lt;/code&gt; variable for the &lt;code&gt;key-auth&lt;/code&gt; plugin in a &lt;code&gt;consumer&lt;/code&gt; and only set it in a route. APISIX will find and use the key for each &lt;code&gt;consumer&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;DRY is not only about code; it's about data management in general. Configuration is data and thus falls under this general umbrella.&lt;/p&gt;

&lt;p&gt;APISIX offers two DRY options: one for &lt;code&gt;upstream&lt;/code&gt; - &lt;code&gt;upstream_id&lt;/code&gt;, and one for &lt;code&gt;plugin&lt;/code&gt; - &lt;code&gt;plugin_config_id&lt;/code&gt;. Upstreams are exclusive; plugins allow for overruling.&lt;/p&gt;

&lt;p&gt;Both mechanisms should help you toward DRYing your configuration and make it more maintainable in the long run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To go further:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;The Don't repeat yourself principle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/terminology/plugin/#plugins-merging-precedence" rel="noopener noreferrer"&gt;Configuration merging precedence&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://blog.frankel.ch/dry-apisix-config/" rel="noopener noreferrer"&gt;A Java Geek&lt;/a&gt; on September 1&lt;sup&gt;st&lt;/sup&gt;, 2024&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dry</category>
      <category>configuration</category>
    </item>
    <item>
      <title>When (not) to write an Apache APISIX plugin</title>
      <dc:creator>Nicolas Fränkel</dc:creator>
      <pubDate>Thu, 29 Aug 2024 09:02:00 +0000</pubDate>
      <link>https://dev.to/apisix/when-not-to-write-an-apache-apisix-plugin-4fpo</link>
      <guid>https://dev.to/apisix/when-not-to-write-an-apache-apisix-plugin-4fpo</guid>
      <description>&lt;p&gt;When I introduce Apache APISIX in my talks, I mention the &lt;a href="https://apisix.apache.org/plugins/" rel="noopener noreferrer"&gt;massive number of existing plugins&lt;/a&gt;, and that each of them implements a specific feature. One of the key features of Apache APISIX is its flexibility. If a feature is missing, you can create your own plugin in Lua or a language compiled into Wasm, showcasing the platform's adaptability to your specific needs. In this post, I aim to provide practical alternatives to writing a custom plugin, offering solutions you can quickly implement in your projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cons of writing a plugin
&lt;/h2&gt;

&lt;p&gt;Before describing alternatives, let me explain the issues of writing a plugin.&lt;/p&gt;

&lt;p&gt;The biggest argument against writing a plugin is quite generic. You write code: suddenly, you need to take care of it. It includes fixing bugs, updating dependencies, keeping the code synchronized with APISIX's latest version, etc.&lt;/p&gt;

&lt;p&gt;As I mentioned above, APISIX comes with a list of out-of-the-box plugins. A huge majority of them are enabled in the default configuration. However, if you want to add a plugin to the list, you must add all required plugins individually, as your configuration replaces the default one; this is the case with a custom plugin.&lt;/p&gt;

&lt;p&gt;Custom plugins require you to configure APISIX with the path to the plugin(s) folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apisix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;extra_lua_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/opt/?.lua&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moreover, some plugins may require additional configuration. For example, in my previous version of &lt;a href="https://www.youtube.com/watch?v=wNg__YYiybo&amp;amp;t=1035s" rel="noopener noreferrer"&gt;Evolving your APIs&lt;/a&gt;, I set a custom nginx snippet to add a Lua shared dictionary to use it in the code's plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;nginx_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;custom_lua_shared_dict&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;plugin-unauth-limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, writing a custom plugin requires a fairly advanced understanding of Apache APISIX and its inner workings. This knowledge is a good idea, but it's not great to make it a requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;vars&lt;/code&gt; and &lt;code&gt;filter_func&lt;/code&gt; parameters
&lt;/h2&gt;

&lt;p&gt;In my earlier blog post &lt;a href="https://blog.frankel.ch/free-tier-api-apisix/" rel="noopener noreferrer"&gt;Free tier API with Apache APISIX&lt;/a&gt;, I implemented an API-free tier with the help of the &lt;code&gt;vars&lt;/code&gt; parameter. As a reminder, &lt;code&gt;vars&lt;/code&gt; is an additional matching condition on your route besides the usual ones: URI, HTTP method, and host.&lt;/p&gt;

&lt;p&gt;In the mentioned post, I used &lt;code&gt;vars&lt;/code&gt; to add a match on an HTTP header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/get&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_apikey"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;~~"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.*"&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;                      &lt;span class="c1"&gt;#1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Match only if the request has an HTTP header named &lt;code&gt;apikey&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, the &lt;code&gt;vars&lt;/code&gt; parameter has its limitations, particularly in its support of a limited range of &lt;a href="https://github.com/api7/lua-resty-expr?tab=readme-ov-file#comparison-operators" rel="noopener noreferrer"&gt;operators&lt;/a&gt;, which may restrict its use in more complex scenarios. Here it is for convenience:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;thead&gt;
    &lt;tr&gt;
        &lt;th&gt;Operator&lt;/th&gt;
        &lt;th&gt;Description&lt;/th&gt;
        &lt;th&gt;Example&lt;/th&gt;
    &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;==&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;equal&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_version", "==", "v2"]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;~=&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;not equal&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_version", "~=", "v2"]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;greater than&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_ttl", "&amp;gt;", 3600]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;greater than or equal to&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_ttl", "&amp;gt;=", 3600]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;less than&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_ttl", "&amp;lt;", 3600]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;⇐&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;less than or equal to&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_ttl", "⇐", 3600]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;~~&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;match &lt;a href="https://www.pcre.org" rel="noopener noreferrer"&gt;RegEx&lt;/a&gt;
&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_env", "~~", "[Dd]ev"]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;~*&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;match &lt;a href="https://www.pcre.org" rel="noopener noreferrer"&gt;RegEx&lt;/a&gt; (case-insensitive)&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_env", "~~", "dev"]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;in&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;exist on the right-hand side&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_version", "in", ["v1","v2"]]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;has&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;contain item on the right-hand side&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["graphql_root_fields", "has", "owner"]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;reverse the adjacent operator&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["arg_env", "!", "~~", "[Dd]ev"]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;ipmatch&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;match an IP address&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;["remote_addr", "ipmatch", ["192.168.102.40", "192.168.3.0/24"]]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note that the DSL also supports boolean operators.&lt;/p&gt;

&lt;p&gt;Imagine that the need goes beyond what we can express with the DSL. It's time to break our bounds and leverage the full power of Lua.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;filter_func&lt;/code&gt;, we can write a dedicated Lua function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It accepts a &lt;code&gt;vars&lt;/code&gt; arg, allowing you to access &lt;a href="https://apisix.apache.org/docs/apisix/apisix-variable/" rel="noopener noreferrer"&gt;APISIX built-in variables&lt;/a&gt;, including nginx variables, &lt;em&gt;e.g.&lt;/em&gt;, HTTP headers.&lt;/li&gt;
&lt;li&gt;It must return a boolean value. As for &lt;code&gt;vars&lt;/code&gt;, APSIX uses the value to decide whether the route matches or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;serverless&lt;/code&gt; plugin
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://apisix.apache.org/docs/apisix/plugins/serverless/" rel="noopener noreferrer"&gt;serverless&lt;/a&gt; plugin actually consists of two plugins: &lt;code&gt;serverless-pre-function&lt;/code&gt; and &lt;code&gt;serverless-pre-function&lt;/code&gt;. As their name implies, the former executes before any other plugin in that phase and the latter after any other plugin in that phase. Note that it's because of their respective default &lt;code&gt;priority&lt;/code&gt;. While it's technically possible to override the priority, common sense should prevent you from ever thinking about doing so.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;serverless&lt;/code&gt;, you configure two parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://apisix.apache.org/docs/apisix/terminology/plugin/#plugins-execution-lifecycle" rel="noopener noreferrer"&gt;phase&lt;/a&gt; in which APISIX executes it&lt;/li&gt;
&lt;li&gt;A sequential array of Lua functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A widespread use case with &lt;code&gt;serverless&lt;/code&gt; is to log input and output data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;
    &lt;span class="n"&gt;upstream_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;serverless&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt;                                             &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"apisix.core"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"conf: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;      &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
              &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ctx : "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;serverless&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;                                                 &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
        &lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"apisix.core"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ctx : "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Execute at the start of the &lt;code&gt;rewrite&lt;/code&gt; phase&lt;/li&gt;
&lt;li&gt;Serialize the configuration to JSON and write it in the log. We use the &lt;code&gt;warn&lt;/code&gt; level because it's the default one&lt;/li&gt;
&lt;li&gt;Serialize the context to JSON and write it in the log&lt;/li&gt;
&lt;li&gt;Execute at the start of the &lt;code&gt;log&lt;/code&gt; phase&lt;/li&gt;
&lt;li&gt;Serialize the context to JSON and write it in the log &lt;strong&gt;again&lt;/strong&gt;. The context will probably have changed between the two phases&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The APISIX model only allows &lt;strong&gt;a unique plugin per route&lt;/strong&gt;. It's a limitation of this approach: while you can have multiple functions per phase, you can't span more than two phases, one for &lt;code&gt;pre&lt;/code&gt; and one for &lt;code&gt;post&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;script&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;I must admit that I learned about &lt;a href="https://apisix.apache.org/docs/apisix/terminology/script/" rel="noopener noreferrer"&gt;script&lt;/a&gt; when researching for this post. With &lt;code&gt;script&lt;/code&gt;, you can write Lua code directly in your config without needing a full-fledged plugin! &lt;code&gt;script&lt;/code&gt; comes with a huge limitation, though: it's exclusive with &lt;code&gt;plugins&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Scripts and Plugins are mutually exclusive, and a Script is executed before a Plugin. This means that after configuring a Script, the Plugin configured on the Route will not be executed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I believe that, at this point, you'd better write a plugin instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;_meta.filter&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;So far, our scope has been the &lt;code&gt;route&lt;/code&gt; (or the &lt;code&gt;service&lt;/code&gt; if you prefer the latter). However, an alternative is to execute a plugin &lt;em&gt;conditionally&lt;/em&gt;. For example, imagine a route configured with the &lt;code&gt;limit-count&lt;/code&gt; plugin to rate limit the number of requests. We want to test the infrastructure in a stress test. Instead of creating our own plugin, we can bypass the plugin if a specific header is present.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;filter&lt;/code&gt; syntax is the same as the &lt;code&gt;vars&lt;/code&gt; syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/get&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;limit-count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                                              &lt;span class="c1"&gt;#1&lt;/span&gt;
        &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="na"&gt;time_window&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
        &lt;span class="na"&gt;rejected_code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;429&lt;/span&gt;
        &lt;span class="na"&gt;_meta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_Secret-Header"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;~="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MySuperDuperSecretBypassKey"&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt; &lt;span class="c1"&gt;#2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Configure the &lt;code&gt;limit-count&lt;/code&gt; plugin&lt;/li&gt;
&lt;li&gt;Execute it only if the HTTP header has a different value&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Writing a custom plugin entails lots of downsides. I showed a couple of other alternatives in this post:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;thead&gt;
    &lt;tr&gt;
        &lt;th&gt;Alternative&lt;/th&gt;
        &lt;th&gt;Scope&lt;/th&gt;
        &lt;th&gt;Feature&lt;/th&gt;
        &lt;th&gt;Comments&lt;/th&gt;
    &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;vars&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;route&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;Additional criterion to match a route&lt;/td&gt;
        &lt;td&gt;Simple DSL with a couple of comparison operators and boolean operators&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;filter_func&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;route&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;Additional criterion to match a route&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Full-fledged Lua function&lt;/li&gt;
                &lt;li&gt;Can access APISIX and nginx variables&lt;/li&gt;
                &lt;li&gt;No access to the context&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;script&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;route&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;Everything a plugin can do&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Exclusive with &lt;code&gt;plugins&lt;/code&gt;
&lt;/li&gt;
                &lt;li&gt;Full access to the context&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;_meta.filter&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;&lt;code&gt;plugin&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;Execute a plugin conditionally&lt;/td&gt;
        &lt;td&gt;Simple DSL with a couple of comparison operators and boolean operators&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Before writing a plugin, I suggest you design your feature using one of the above alternatives (but &lt;code&gt;script&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To go further:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/terminology/plugin/" rel="noopener noreferrer"&gt;Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/terminology/script/" rel="noopener noreferrer"&gt;Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/api7/lua-resty-expr" rel="noopener noreferrer"&gt;lua-resty-expr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.api7.ai/apisix/reference/plugin-common-configurations" rel="noopener noreferrer"&gt;Plugin Common Configurations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://blog.frankel.ch/when-write-apisix-plugin/" rel="noopener noreferrer"&gt;A Java Geek&lt;/a&gt; on August 25&lt;sup&gt;th&lt;/sup&gt;, 2024&lt;/em&gt;&lt;/p&gt;

</description>
      <category>apacheapisix</category>
      <category>plugin</category>
      <category>lua</category>
      <category>programming</category>
    </item>
    <item>
      <title>Free tier API with Apache APISIX</title>
      <dc:creator>Nicolas Fränkel</dc:creator>
      <pubDate>Thu, 01 Aug 2024 09:02:00 +0000</pubDate>
      <link>https://dev.to/apisix/free-tier-api-with-apache-apisix-5cgo</link>
      <guid>https://dev.to/apisix/free-tier-api-with-apache-apisix-5cgo</guid>
      <description>&lt;p&gt;Lots of service providers offer a free tier of their service. The idea is to let you kick their service's tires freely. If you need to go above the free tier at any point, you'll likely stay on the service and pay. In this day and age, most services are online and accessible via an API. Today, we will implement a free tier with &lt;a href="https://apisix.apache.org/" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A naive approach
&lt;/h2&gt;

&lt;p&gt;I implemented a free tier in my post &lt;a href="https://blog.frankel.ch/evolve-apis/#know-your-users" rel="noopener noreferrer"&gt;Evolving your RESTful APIs, a step-by-step approach&lt;/a&gt;, albeit in a very naive way. I copy-pasted the &lt;a href="https://apisix.apache.org/docs/apisix/plugins/limit-count/" rel="noopener noreferrer"&gt;limit-count&lt;/a&gt; plugin and added my required logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;_M&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ver: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf_version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- no limit if the request is authenticated&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                               &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;consumer_conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer_mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"key-auth"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                       &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;consumer_conf&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;consumers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lrucache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"consumers_key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer_conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf_version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
                    &lt;span class="n"&gt;create_consume_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer_conf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;                                         &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;                                                        &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;-- rest of the logic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Get the configured request header value&lt;/li&gt;
&lt;li&gt;Get the consumer's &lt;code&gt;key-auth&lt;/code&gt; configuration&lt;/li&gt;
&lt;li&gt;Get consumers&lt;/li&gt;
&lt;li&gt;Get the consumer with the passed API key if they exist&lt;/li&gt;
&lt;li&gt;If they exist, bypass the rate limiting logic&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The downside of this approach is that the code is now my own. It has evolved since I copied it, and I'm stuck with the version I copied. We can do better, with the help of the &lt;code&gt;vars&lt;/code&gt; parameter on routes.&lt;/p&gt;
&lt;h2&gt;
  
  
  APISIX route matching
&lt;/h2&gt;

&lt;p&gt;APISIX delegates its matching rule to a &lt;a href="https://apisix.apache.org/docs/apisix/terminology/router/" rel="noopener noreferrer"&gt;router&lt;/a&gt;.&lt;br&gt;
Standard matching parameters include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The URI&lt;/li&gt;
&lt;li&gt;The HTTP method. By default, all methods match.&lt;/li&gt;
&lt;li&gt;The host&lt;/li&gt;
&lt;li&gt;The remote address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most users do match on the URI; a small minority use HTTP methods and the host. However, they are not the only matching parameters. Knowing the rest will bring you into the world of advanced users of APISIX.&lt;/p&gt;

&lt;p&gt;Let's take a simple example, header-based API versioning. You'd need actually to match a specific HTTP request header. I've already described how to do it &lt;a href="https://blog.frankel.ch/api-versioning/" rel="noopener noreferrer"&gt;previously&lt;/a&gt;. In essence, &lt;code&gt;vars&lt;/code&gt; is an additional matching criterion that allows the evaluation of APISIX and nginx variables.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v1+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above route will match if, and only if, the HTTP &lt;code&gt;Accept&lt;/code&gt; header is equal to &lt;code&gt;vnd.ch.frankel.myservice.v1+json&lt;/code&gt;. You can find the complete list of supported operators in the &lt;a href="https://github.com/api7/lua-resty-expr" rel="noopener noreferrer"&gt;lua-resty-expr&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;APISIX matches routes in a non-specified order by default. If URIs are &lt;em&gt;disjointed&lt;/em&gt;, that's not an issue.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v1+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v2+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Problems arise when URIs are somehow not disjointed. For example, imagine I want to set a default route for unversioned calls.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v1+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v2+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We need the third route to be evaluated last. If it's evaluated first, it will match all requests, regardless of their HTTP headers. APISIX offers the &lt;code&gt;priority&lt;/code&gt; parameter to order route evaluation. By default, a route's priority is 0. Let's use &lt;code&gt;priority&lt;/code&gt; to implement the versioning correctly:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v1+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;                                              &lt;span class="c1"&gt;#1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_accept"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=="&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vnd.ch.frankel.myservice.v2+json"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;                                              &lt;span class="c1"&gt;#1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Evaluated first. The order is not relevant since the URIs are disjointed.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Implementing free tier with matching rules
&lt;/h2&gt;

&lt;p&gt;We are now ready to implement our free tier with matching rules.&lt;/p&gt;

&lt;p&gt;The first route to be evaluated should be the one with authentication and no rate limit:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/get&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_apikey"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;~~"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.*"&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;                      &lt;span class="c1"&gt;#1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key-auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~&lt;/span&gt;                                             &lt;span class="c1"&gt;#2&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;                                              &lt;span class="c1"&gt;#3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Match if the request has an HTTP header named &lt;code&gt;apikey&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Authenticate the request&lt;/li&gt;
&lt;li&gt;Evaluate first&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The other route is evaluated afterward.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/get&lt;/span&gt;
    &lt;span class="na"&gt;upstream_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;limit-count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                            &lt;span class="c1"&gt;#1&lt;/span&gt;
        &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="na"&gt;time_window&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
        &lt;span class="na"&gt;rejected_code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;429&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Rate limit this route&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you configure APISIX with the above snippets, and it receives a request to &lt;code&gt;/get&lt;/code&gt;, it tries to match the first route &lt;em&gt;only&lt;/em&gt; if it has an &lt;code&gt;apikey&lt;/code&gt; request header:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If it has one:

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;key-auth&lt;/code&gt; plugin kicks in&lt;/li&gt;
&lt;li&gt;If it succeeds, APISIX forwars the request to the upstream&lt;/li&gt;
&lt;li&gt;If it fails, APISIX returns a 403 HTTP status code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If it has no such request header, it matches the second route with a rate limit.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A free tier is a must for any API service provider worth its salt. In this post, I've explained how to configure such free tier with Apache APISIX.&lt;/p&gt;

&lt;p&gt;The complete source code for this post can be found on GitHub:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ajavageek" rel="noopener noreferrer"&gt;
        ajavageek
      &lt;/a&gt; / &lt;a href="https://github.com/ajavageek/free-tier-apisix" rel="noopener noreferrer"&gt;
        free-tier-apisix
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;To go further:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/terminology/consumer/" rel="noopener noreferrer"&gt;Consumer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/plugins/limit-count/" rel="noopener noreferrer"&gt;limit-count plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apisix.apache.org/docs/apisix/router-radixtree/" rel="noopener noreferrer"&gt;router-radixtree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/api7/lua-resty-expr" rel="noopener noreferrer"&gt;lua-resty-expr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://blog.frankel.ch/free-tier-api-apisix/" rel="noopener noreferrer"&gt;A Java Geek&lt;/a&gt; on July 28&lt;sup&gt;th&lt;/sup&gt;, 2024&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>apacheapisix</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
