kayx23 commented on code in PR #1790: URL: https://github.com/apache/apisix-website/pull/1790#discussion_r1580435982
########## blog/en/blog/2024/05/02/pass-parameters-apisix.md: ########## @@ -0,0 +1,296 @@ +--- +title: Five ways to pass parameters to Apache APISIX +authors: + - name: Nicolas Fränkel + title: Author + url: https://github.com/nfrankel + image_url: https://avatars.githubusercontent.com/u/752258 +keywords: + - APISIX + - REST + - HTTP API +description: > + 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. +tags: [Community] +image: https://static.apiseven.com/uploads/2024/04/25/V05nSV5W_american-football-63109.jpg +--- + +<head> + <link rel="canonical" href="https://blog.frankel.ch/fix-duplicate-api-requests/" /> +</head> + +>I recently read [6 Ways To Pass Parameters to Spring REST API](https://javabulletin.substack.com/p/6-ways-to-pass-parameters-to-spring). 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. + +<!--truncate--> + +## 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 regexp API + +Let's try: + +```bash +curl localhost:9080/path/15/3 +``` + +The log displays: + +``` +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](https://apisix.apache.org/docs/apisix/terminology/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: + +``` +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 regexp: Review Comment: `regexp` -- > `RegEx` ? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
