Skip to main content

Version: 3.10.x

a7-plugin-serverless

Overview

API7 Enterprise Edition (API7 EE) provides two serverless plugins that execute inline Lua functions during request processing:

  • serverless-pre-function — runs at the beginning of the specified phase (priority 10000, executes early).
  • serverless-post-function — runs at the end of the specified phase (priority −2000, executes late).

Both share identical configuration. Functions are defined as Lua strings in the Admin API and compiled at load time.

When to Use

  • Inject custom request/response logic without writing a full plugin.
  • Quick prototyping of header injection, redirects, or logging.
  • Add lightweight pre-processing (rewrite) or post-processing (log).
  • Dynamic routing decisions based on request attributes.

Plugin Configuration Reference

FieldTypeRequiredDefaultValid ValuesDescription
phasestringNo"access"rewrite, access, header_filter, body_filter, log, before_proxyPhase when functions execute
functionsarray[string]YesLua function stringsFunctions executed sequentially; each must return a function

Function Signature

Since API7 EE (based on APISIX v2.6+), functions receive two arguments:

return function(conf, ctx)
-- conf: plugin configuration object
-- ctx: API7 EE request context (shared across plugins)
--
-- Optional return:
-- return code, body -- exit immediately with HTTP status + body
-- return -- continue to next function / plugin
end

Rules:

  • The string MUST return a function. Raw statements are rejected.
  • Functions are cached via LRU cache; update the route to pick up changes.

Phase Execution Order

1. rewrite         → modify request before routing
2. access → authorization / authentication checks
3. before_proxy → last chance before upstream call
4. header_filter → modify response headers
5. body_filter → modify response body (chunked via ngx.arg)
6. log → logging after response sent (read-only)

Phase Restrictions

PhaseCan Read RequestCan Modify RequestCan Modify ResponseCan Exit
rewrite
access
before_proxy
header_filter✅ (headers)
body_filter✅ (body chunks)
log

Step-by-Step Examples

1. Basic Logging

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "serverless-log",
"uri": "/api/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function() ngx.log(ngx.WARN, 'incoming request: ', ngx.var.uri) end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

2. HTTP to HTTPS Redirect

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "force-https",
"uri": "/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function() if ngx.var.scheme == 'http' then ngx.header['Location'] = 'https://' .. ngx.var.host .. ngx.var.request_uri; ngx.exit(301) end end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

3. Request Header Injection

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "inject-headers",
"uri": "/api/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function(conf, ctx) ngx.req.set_header('X-Request-ID', ngx.var.request_id); ngx.req.set_header('X-Real-IP', ngx.var.remote_addr) end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

4. Modify Upstream URI

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "rewrite-uri",
"uri": "/legacy/*",
"plugins": {
"serverless-post-function": {
"phase": "access",
"functions": [
"return function(conf, ctx) ctx.var.upstream_uri = '/v2' .. ngx.var.uri end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

5. Response Header Modification (header_filter phase)

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "resp-headers",
"uri": "/api/*",
"plugins": {
"serverless-post-function": {
"phase": "header_filter",
"functions": [
"return function() ngx.header['X-Processed-By'] = 'API7-EE'; ngx.header['X-Response-Time'] = ngx.now() - ngx.req.start_time() end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

6. Closure with Persistent State

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "closure-counter",
"uri": "/count",
"plugins": {
"serverless-pre-function": {
"phase": "log",
"functions": [
"local count = 0; return function() count = count + 1; ngx.log(ngx.WARN, 'request count: ', count) end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

7. Multiple Sequential Functions

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "multi-fn",
"uri": "/api/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function() ngx.log(ngx.WARN, 'step one') end",
"return function() ngx.log(ngx.WARN, 'step two') end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

8. Custom Authentication Guard

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "custom-auth",
"uri": "/admin/*",
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": [
"return function() local token = ngx.var.http_authorization; if not token or token ~= 'Bearer secret123' then return 401, '{\"error\":\"unauthorized\"}' end end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

Available Lua APIs

Core ngx APIs

-- Request
ngx.var.uri, ngx.var.request_uri, ngx.var.scheme, ngx.var.host
ngx.var.remote_addr, ngx.var.request_method, ngx.var.request_id
ngx.req.get_headers(), ngx.req.get_uri_args(), ngx.req.get_method()
ngx.req.set_header(name, value), ngx.req.read_body(), ngx.req.get_body_data()

-- Response
ngx.header["Name"] = "value"
ngx.status = 200
ngx.say(data), ngx.print(data)
ngx.exit(status), ngx.redirect(uri, status)

-- Logging
ngx.log(ngx.ERR, msg), ngx.log(ngx.WARN, msg), ngx.log(ngx.INFO, msg)

-- Utilities
ngx.time(), ngx.now(), ngx.encode_base64(str), ngx.decode_base64(str)

API7 EE Context Variables

ctx.var.upstream_uri = "/new/path"   -- modify upstream request URI
ctx.curr_req_matched._path -- matched route path
ctx.consumer_name -- authenticated consumer name
ctx.route_id -- current route ID
ctx.service_id -- current service ID

Available Libraries

local json = require("cjson")
local core = require("apisix.core")
local http = require("resty.http")
local lrucache = require("resty.lrucache")

Config Sync Example

version: "1"
gateway_group: default
routes:
- id: serverless-demo
uri: /api/*
plugins:
serverless-pre-function:
phase: rewrite
functions:
- "return function() ngx.req.set_header('X-Gateway', 'api7-ee') end"
serverless-post-function:
phase: log
functions:
- "return function() ngx.log(ngx.WARN, 'request completed') end"
upstream:
type: roundrobin
nodes:
- host: backend
port: 8080
weight: 1

Key Differences: Pre vs Post

Featureserverless-pre-functionserverless-post-function
ExecutionBeginning of phaseEnd of phase
Priority10000 (high — runs early)−2000 (low — runs late)
Typical UsePre-processing, auth guardsPost-processing, logging

Troubleshooting

SymptomCauseFix
only accept Lua function, the input code type is nilFunction string doesn't return a functionWrap code in return function() ... end
failed to compile functionSyntax error in Lua codeTest code in a Lua REPL first
Function changes not taking effectLRU cache holds old compiled functionUpdate route to trigger recompilation
ngx.say not working in header_filterPhase restriction — cannot write body in header_filterUse header_filter only for ngx.header modifications
No output in log phaseLog phase is read-onlyUse ngx.log() instead of ngx.say()
Blocking I/O causes timeoutSynchronous operations in request pathUse ngx.timer.at() for async work

This page is generated from a7-plugin-serverless/SKILL.md in the api7/a7 repository. Browse all skills on the AI Agent Skills page.

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation