public-api
The public-api plugin exposes an internal API endpoint, making it publicly accessible. One of the primary use cases of this plugin is to expose internal endpoints created by other plugins.
Examples
The examples below demonstrate how you can configure public-api in different scenarios.
Expose Prometheus Metrics at Custom Endpoint
The following example demonstrates how you can disable the Prometheus export server that, by default, exposes an endpoint on port 9091, and expose APISIX Prometheus metrics on a new public API endpoint on port 9080, which APISIX uses to listen to other client requests.
You will also configure the route such that the internal endpoint /apisix/prometheus/metrics is exposed at a custom endpoint.
If a large quantity of metrics is being collected, the plugin could take up a significant amount of CPU resources for metric computations and negatively impact the processing of regular requests.
To address this issue, APISIX uses privileged agent and offloads the metric computations to a separate process. This optimization applies automatically if you use the metric endpoint configured under plugin_attr.prometheus.export_addr in the configuration file. If you expose the metric endpoint with the public-api plugin, you will not benefit from this optimization.
To expose metrics through public-api, first disable the default Prometheus export server:
- Host or Docker
- Kubernetes (Helm)
Add or update this section in the gateway configuration file:
plugin_attr:
prometheus:
enable_export_server: false
Reload the gateway for changes to take effect.
For Helm deployments, update the chart values that render plugin_attr.prometheus. Keep the rest of your values file unchanged.
For the APISIX Helm chart, set the following values:
apisix:
pluginAttrs:
prometheus:
enable_export_server: false
For the API7 Gateway Helm chart, set the following values:
pluginAttrs:
prometheus:
enable_export_server: false
Then apply the values file with the chart used for this gateway release:
helm upgrade <release-name> <chart-name> -n <namespace> -f values.yaml
Next, create a route with public-api plugin and expose a public API endpoint for APISIX metrics:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "prometheus-metrics",
"uri": "/prometheus_metrics",
"plugins": {
"public-api": {
"uri": "/apisix/prometheus/metrics"
}
}
}'
services:
- name: public-api-metrics-service
routes:
- name: prometheus-metrics
uris:
- /prometheus_metrics
plugins:
public-api:
uri: /apisix/prometheus/metrics
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
name: httpbin-external-domain
namespace: aic
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
protocol: TCP
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: prometheus-metrics
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /prometheus_metrics
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: public-api-metrics-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: public-api-metrics-plugin-config
spec:
plugins:
- name: public-api
config:
uri: /apisix/prometheus/metrics
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: prometheus-metrics
spec:
ingressClassName: apisix
http:
- name: prometheus-metrics
match:
paths:
- /prometheus_metrics
plugins:
- name: public-api
enable: true
config:
uri: /apisix/prometheus/metrics
Apply the configuration:
kubectl apply -f public-api-ic.yaml
❶ Set the route uri to the custom endpoint path.
❷ Set the plugin uri to the internal endpoint to be exposed.
The ADC and Gateway API tabs include a conventional backend. When the plugin handles the request itself, the backend is not contacted. Verify the plugin-specific result below; a backend response alone does not confirm that the plugin ran.
Send a request to the custom metrics endpoint:
curl "http://127.0.0.1:9080/prometheus_metrics"
You should see an output similar to the following:
# HELP apisix_http_requests_total The total number of client requests since APISIX started
# TYPE apisix_http_requests_total gauge
apisix_http_requests_total 1
# HELP apisix_nginx_http_current_connections Number of HTTP connections
# TYPE apisix_nginx_http_current_connections gauge
apisix_nginx_http_current_connections{state="accepted"} 1
apisix_nginx_http_current_connections{state="active"} 1
apisix_nginx_http_current_connections{state="handled"} 1
apisix_nginx_http_current_connections{state="reading"} 0
apisix_nginx_http_current_connections{state="waiting"} 0
apisix_nginx_http_current_connections{state="writing"} 1
...
Expose Batch Requests Endpoint
The following example uses public-api to expose an endpoint for batch-requests. Clients can send multiple requests to the gateway in one HTTP call and receive the combined results.
The gateway must load batch-requests in its static plugin list. APISIX does not load this plugin by default. Preserve the existing plugin list, add batch-requests, and reload the gateway before continuing.
Create a sample route to httpbin's /anything endpoint for verification:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "httpbin-anything",
"uri": "/anything",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: httpbin
routes:
- name: httpbin-anything
uris:
- /anything
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: httpbin-anything
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: httpbin-anything
spec:
ingressClassName: apisix
http:
- name: httpbin-anything
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
Apply the configuration:
kubectl apply -f public-api-httpbin-ic.yaml
Create a route with public-api plugin and set the route uri to the internal endpoint to be exposed:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "batch-requests",
"uri": "/apisix/batch-requests",
"plugins": {
"public-api": {}
}
}'
services:
- name: public-api-batch-service
routes:
- name: batch-requests
uris:
- /apisix/batch-requests
plugins:
public-api: {}
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
name: httpbin-external-domain
namespace: aic
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
protocol: TCP
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: public-api-batch-plugin-config
spec:
plugins:
- name: public-api
config: {}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: batch-requests
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /apisix/batch-requests
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: public-api-batch-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: batch-requests
spec:
ingressClassName: apisix
http:
- name: batch-requests
match:
paths:
- /apisix/batch-requests
plugins:
- name: public-api
enable: true
Apply the configuration:
kubectl apply -f public-api-batch-ic.yaml
Send a pipelined request consisting of a GET and a POST request to the exposed batch requests endpoint:
curl "http://127.0.0.1:9080/apisix/batch-requests" -X POST -d '
{
"pipeline": [
{
"method": "GET",
"path": "/anything"
},
{
"method": "POST",
"path": "/anything",
"body": "a post request"
}
]
}'
You should receive responses from both requests, similar to the following:
[
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-5a30174f5534287928c54ca9\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"GET\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
},
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"a post request\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Content-Length\": \"14\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-0eddcec07f154dac0d77876f\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"POST\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
}
]
If you would like to expose the batch requests endpoint at a custom endpoint, create a route with public-api plugin as such:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "batch-requests",
"uri": "/batch-requests",
"plugins": {
"public-api": {
"uri": "/apisix/batch-requests"
}
}
}'
services:
- name: public-api-batch-service
routes:
- name: batch-requests
uris:
- /batch-requests
plugins:
public-api:
uri: /apisix/batch-requests
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
name: httpbin-external-domain
namespace: aic
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
protocol: TCP
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: batch-requests
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /batch-requests
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: public-api-batch-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: public-api-batch-plugin-config
spec:
plugins:
- name: public-api
config:
uri: /apisix/batch-requests
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: batch-requests
spec:
ingressClassName: apisix
http:
- name: batch-requests
match:
paths:
- /batch-requests
plugins:
- name: public-api
enable: true
config:
uri: /apisix/batch-requests
Apply the configuration:
kubectl apply -f public-api-batch-ic.yaml
❶ Set the route uri to the custom endpoint path.
❷ Set the plugin uri to the internal endpoint to be exposed.
The batch requests endpoint should now be exposed as /batch-requests, instead of /apisix/batch-requests.
Send a pipelined request consisting of a GET and a POST request to the exposed batch requests endpoint:
curl "http://127.0.0.1:9080/batch-requests" -X POST -d '
{
"pipeline": [
{
"method": "GET",
"path": "/anything"
},
{
"method": "POST",
"path": "/anything",
"body": "a post request"
}
]
}'
You should receive responses from both requests, similar to the following:
[
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-5a30174f5534287928c54ca9\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"GET\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
},
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"a post request\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Content-Length\": \"14\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-0eddcec07f154dac0d77876f\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"POST\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
}
]