DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Why Mocking Sucks
  • How to Enhance the Performance of .NET Core Applications for Large Responses
  • Automatic 1111: Adding Custom APIs
  • Create Proxy Application for Mule APIs

Trending

  • How Large Tech Companies Architect Resilient Systems for Millions of Users
  • Accelerating Debugging in Integration Testing: An Efficient Search-Based Workflow for Impact Localization
  • Navigating Double and Triple Extortion Tactics
  • Traditional Testing and RAGAS: A Hybrid Strategy for Evaluating AI Chatbots
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Five Ways To Pass Parameters to Apache APISIX

Five Ways To Pass Parameters to Apache APISIX

This article explores all the ways to send parameters to Apache APISIX, which is beneficial when you write a custom plugin.

By 
Nicolas Fränkel user avatar
Nicolas Fränkel
DZone Core CORE ·
May. 02, 24 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
1.8K Views

Join the DZone community and get the full member experience.

Join For Free

I recently read 6 Ways To Pass Parameters to Spring REST API. Though the title is a bit misleading, as it's unrelated to REST, it does an excellent job listing all ways to send parameters to a Spring application. I want to do the same for Apache APISIX; it's beneficial when you write a custom plugin.

General Setup

The general setup uses Docker Compose and static configuration. I'll have one plugin per way to pass parameters.

YAML
 
services:
  httpbin:
    image: kennethreitz/httpbin                                         #1
  apisix:
    image: apache/apisix:3.9.0-debian
    volumes:
      - ./apisix/conf/config.yml:/usr/local/apisix/conf/config.yaml:ro
      - ./apisix/conf/apisix.yml:/usr/local/apisix/conf/apisix.yaml:ro  #2
      - ./apisix/plugins:/opt/apisix/plugins:ro                         #3
    ports:
      - "9080:9080"


  1. Local httpbin for more reliable results and less outbound network traffic
  2. Static configuration file
  3. Plugins folder, one file per plugin
YAML
 
deployment:
  role: data_plane
  role_data_plane:
    config_provider: yaml                                              #1
apisix:
  extra_lua_path: /opt/?.lua                                           #2
plugins:
  - proxy-rewrite                                                      #3
  - path-variables                                                     #4
# ...  


  1. Set static configuration
  2. Use every Lua file under /opt/apisix/plugins as a plugin
  3. Regular plugin
  4. Custom plugin, one per alternative

Path Variables

Path variables are a straightforward way to pass data. Their main issue is that they are limited to simple values, e.g., /links/{n}/{offset}. The naive approach is to write the following Lua code:

Lua
 
local core = require("apisix.core")

function _M.access(_, ctx)
    local captures, _ = ngx.re.match(ctx.var.uri, '/path/(.*)/(.*)')  --1-2
    for k, v in pairs(captures) do
        core.log.warn('Order-Value pair: ', k, '=', v)
    end
end


  1. APISIX stores the URI in ctx.var.uri
  2. Nginx offers a regular expression API

Let's try:

Shell
 
curl localhost:9080/path/15/3


The log displays:

Plain Text
 
Order-Value pair: 0=/path/15/3
Order-Value pair: 1=15
Order-Value pair: 2=3


I didn't manage errors, though. Alternatively, we can rely on Apache APISIX features: a specific router. The default router, radixtree_host_uri, uses both the host and the URI to match requests. radixtree_uri_with_parameter lets go of the host part but also matches parameters.

YAML
 
apisix:
  extra_lua_path: /opt/?.lua
  router:
    http: radixtree_uri_with_parameter


We need to update the route:

YAML
 
routes:
  - path-variables
  - uri: /path/:n/:offset                                              #1
    upstream_id: 1
    plugins:
      path-variables: ~


  1. Store n and offset in the context, under ctx.curr_req_matched

We keep the plugin just to log the path variables:

Lua
 
function _M.access(_, ctx)
    core.log.warn('n: ', ctx.curr_req_matched.n, ', offset: ', ctx.curr_req_matched.offset)
end


The result is as expected with the same request as above:

Plain Text
 
n: 15, offset: 3


Query Parameters

Query parameters are another regular way to pass data. Like path variables, you can only pass simple values, e.g., /?foo=bar. The Lua code doesn't require regular expressions:

Lua
 
local core = require("apisix.core")

function _M.access(_, _)
    local args, _ = ngx.req.get_uri_args()
    for k, v in pairs(args) do
        core.log.warn('Order-Value pair: ', k, '=', v)
    end
end


Let's try:

Shell
 
curl localhost:9080/query\?foo=one\&bar=three


The log displays:

Plain Text
 
Key-Value pair: bar=three
Key-Value pair: foo=one


Remember that query parameters have no order.

Our code contains an issue, though. The ngx.req.get_uri_args() accepts parameters. Remember that the client can pass a query parameter multiple times with different values, e.g., ?foo=one&foo=two? The first parameter is the maximum number of values returned for a single query parameter. To avoid ignoring value, we should set it to 0, i.e., unbounded.

Since every plugin designer must remember it, we can add the result to the context for other plugins down the chain. The updated code looks like this:

Lua
 
local core = require("apisix.core")

function _M.get_uri_args(ctx)
    if not ctx then
        ctx = ngx.ctx.api_ctx
    end
    if not ctx.req_uri_args then
        local args, _ = ngx.req.get_uri_args(0)
        ctx.req_uri_args = args
    end
    return ctx.req_uri_args
end

function _M.access(_, ctx)
    for k, v in pairs(ctx.req_uri_args) do
        core.log.warn('Key-Value pair: ', k, '=', v)
    end
end


Request Headers

Request headers are another way to pass parameters. While they generally only contain simple values, you can also use them to send structured values, e.g., JSON. Depending on your requirement, APISIX can list all request headers or a specific one. Here, I get all of them:

Lua
 
local core = require("apisix.core")

function _M.access(_, _)
    local headers = core.request.headers()
    for k, v in pairs(headers) do
        core.log.warn('Key-Value pair: ', k, '=', v)
    end
end


We test with a simple request:

Shell
 
curl -H 'foo: 1' -H 'bar: two'  localhost:9080/headers


And we got more than we expected because curl added default headers:

Plain Text
 
Key-Value pair: user-agent=curl/8.4.0
Key-Value pair: bar=two
Key-Value pair: foo=1
Key-Value pair: host=localhost:9080
Key-Value pair: accept=*/*


Request Body

Setting a request body is the usual way to send structured data, e.g, JSON. Nginx offers a simple API to collect such data.

Lua
 
local core = require("apisix.core")

function _M.access(_, _)
    local args = core.request.get_post_args()                          --1
    local body = next(args, nil)                                       --2
    core.log.warn('Body: ', body)
end


  1. Access the body as a regular Lua table
  2. A table is necessary in case of multipart payloads, e.g., file uploads. Here, we assume there's a single arg, the content body.

It's time to test:

Shell
 
curl  localhost:9080/body -X POST -d '{ "foo": 1, "bar": { "baz": "two" } }'


The result is as expected:

JSON
 
Body: { "foo": 1, "bar": { "baz": "two" } }


Cookies

Last but not least, we can send parameters via cookies. The difference with previous alternatives is that cookies persist on the client side, and the browser sends them with each request. On the Lua side, we need to know the cookie name instead of listing all query parameters or headers.

Lua
 
local core = require("apisix.core")

function _M.access(_, ctx)
    local foo = ctx.var.cookie_foo                                     --1
    core.log.warn('Cookie value: ', foo)
end


  1. The cookie is named foo and is case-insensitive

Let's test:

Shell
 
curl --cookie "foo=Bar"  localhost:9080/cookies


The result is correct:

Plain Text
 
Cookie value: Bar


Summary

In this post, we listed five alternatives to pass parameters server-side and explained how to access them on Apache APISIX. Here's the API summary:

Alternative Source API
Path variable APISIX Router Use the radixtree_uri_with_parameter router
Query parameter Nginx ngx.req.get_uri_args(0)
Request header APISIX core lib core.request.headers()
Request body APISIX core lib core.request.get_post_args()
Cookie Method context parameter ctx.var.cookie_


Thanks a lot to Zeping Bai for his review and explanations.

The complete source code for this post can be found on GitHub.

To Go Further

  • 6 Ways To Pass Parameters to Spring REST API
  • How to Build an Apache APISIX Plugin From 0 to 1?
API Uniform Resource Identifier Coding best practices application

Published at DZone with permission of Nicolas Fränkel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Why Mocking Sucks
  • How to Enhance the Performance of .NET Core Applications for Large Responses
  • Automatic 1111: Adding Custom APIs
  • Create Proxy Application for Mule APIs

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!