zenozeng opened a new issue #5106:
URL: https://github.com/apache/apisix/issues/5106


   ### Issue description
   
   ## Abstract
   Apache APISIX has been supporting writing customized plugins using Lua, 
Java, Go and Python. 
   I propose to add JavaScript Plugin Runner for Apache APISIX.
   ## Background
   ### JavaScript is widely used
   JavaScript is a widely used dynamic language. According to SlashData, 
JavaScript, which includes CoffeeScript and TypeScript in the survey, is by far 
the most popular language, with 12.4 million developers using it worldwide.
   ​
   Apache APISIX has been supporting writing customized plugins using Lua, 
Java, Go and Python. 
   LuaJIT is really fast, and Lua is very easy to learn. But out-of-the-box 
JavaScript plugin runner will unlock more developers with JavaScript background 
for Apache APISIX.
   ### Node.js and Deno
   Node.js is the most popular JavaScript runtime built on Chrome's V8 
JavaScript engine.
   [Deno](https://github.com/denoland/deno), yet another JavaScript runtime 
built on V8, with 77.9K stars on GitHub, was created by 
[ry](https://github.com/ry) (creator of Node.js) to address his [10 Things I 
Regret About Node.js](https://www.youtube.com/watch?v=M3BM9TB-8yA).
   It would be nice if APISIX provides first class support for both Node.js and 
Deno.
   ### WebAssembly support
   Supporting WebAssembly in Apache APISIX has been discussed at 
[https://github.com/apache/apisix/issues/157](https://github.com/apache/apisix/issues/157).
   Both Node.js and Deno can execute WebAssembly modules.
   1. ​[https://nodejs.org/api/wasi.html](https://nodejs.org/api/wasi.html)
   1. 
[https://deno.land/[email protected]/getting_started/webassembly](https://deno.land/[email protected]/getting_started/webassembly)
   
   There are many WebAssembly runtime, including but not limited to
   1. [Wasmtime](https://github.com/bytecodealliance/wasmtime), a [Bytecode 
Alliance](https://bytecodealliance.org/) project ([the Wasmtime team is moving 
to Fastly](https://bytecodealliance.org/articles/1-year-update))
   1. [WasmEdge](https://github.com/WasmEdge/WasmEdge) (formerly SSVM), open 
sourced by Second State, a CNCF project
   1. [Wasmer](https://github.com/wasmerio/wasmer), [used by 
Dart](https://github.com/dart-lang/wasm)
   1. [Lucet](https://github.com/bytecodealliance/lucet), open sourced by 
Fastly, a [Bytecode Alliance](https://bytecodealliance.org/) project (in the 
medium-to-long term, the plan is to [merge Lucet and 
Wasmtime](https://bytecodealliance.org/articles/1-year-update))
   
   It's possible to support WebAssembly in JavaScript Plugin Runner, but maybe 
a separated Apache APISIX WebAssembly Runner is better?
   ## Proposal
   To address the problems described above, I propose to add JavaScript Plugin 
Runner for Apache APISIX. It will provide first class support for both Node.js 
and Deno.
   ## Demo Implementation
   I have created a demo implementation: 
[https://github.com/zenozeng/apisix-javascript-plugin-runner](https://github.com/zenozeng/apisix-javascript-plugin-runner).
   ### Plugin Example
   ```yaml
   # examples/config.yaml
   ext-plugin:
     cmd: 
       - "/usr/local/apisix/javascript-plugin-runner/bin/runner"
       - "/usr/local/apisix/javascript-plugin-runner/examples/say.js"
   
   apisix:
     port_admin: 9180
     admin_key:
       -
         name: "admin"
         key: "YOUR_ADMIN_KEY"
         role: admin
   
   etcd:
     host:
       - "http://etcd:2379";
   ```
   ```typescript
   class SayPlugin {
   
       getName() {
           return "say"
       }
   
       parseConf(conf) {
           return JSON.parse(conf)
       }
   
       // Filter will be executed on every request with the say plugin 
configured.
       async filter(conf, request, response) {
           const headers = new Map()
           headers.set('X-Resp-A6-JavaScript-Plugin', 'Say')
           response.body = conf.body
           response.headers = headers
       }
   
   }
   
   module.exports = SayPlugin
   ```
   ```shell
   # default config.apisix.allow_admin is 127.0.0.0/24, using docker exec
   docker exec -it apisix curl -H "Content-Type: application/json" \
       -H 'X-API-KEY: YOUR_ADMIN_KEY' \
       -X PUT \
       --data 
'{"uri":"/say","methods":["PUT","GET"],"plugins":{"ext-plugin-pre-req":{"conf":[{"name":"say","value":"{\"body\":\"123\"}"}]}}}'
 \
       http://127.0.0.1:9180/apisix/admin/routes/1
   ```
   ```shell
   curl -v http://127.0.0.1:9080/say
   
   < HTTP/1.1 200 OK
   < Date: Fri, 09 Jul 2021 18:20:24 GMT
   < Content-Type: text/plain; charset=utf-8
   < Transfer-Encoding: chunked
   < Connection: keep-alive
   < X-Resp-A6-JavaScript-Plugin: Say
   < Server: APISIX/2.7
   < 
   * Connection #0 to host 127.0.0.1 left intact
   123
   ```
   ### Interface
   ```typescript
   interface Plugin {
       getName(): string
       parseConf(conf: string): string
       filter(conf: Object, request: Request, response: Response): Promise<void>
   }
   
   interface Request {
       // The id is for debug. It will be recycled when the number is exhausted
       id: number;
   
       // the path of the request.
       path: string;
   
       // The associated Headers object of the request.
       // See·https://developer.mozilla.org/en-US/docs/Web/API/Headers
       headers: Headers;
   
       srcIp: number[];
   
       // Request's method (GET, POST, etc.)
       method: string;
   
       // The associated Args object of the request.
       args: Args;
   }
   
   
   interface Args {
       keys(): Iterable<string>
       get(k: string): string
       set(k: string, v: string): Args
   }
   
   interface Headers {
       keys(): Iterable<string>
       get(k: string): string
       set(k: string, v: string): Headers
   }
   
   interface Response {
       // The status code of the response (200, 404, etc.)
       status?: number;
       // The associated Headers object of the response.
       // See https://developer.mozilla.org/en-US/docs/Web/API/Headers
       headers?: Headers;
       // The body of the response
       body?: Uint8Array | string;
   }
   ```
   ## References
   
   1. 
[https://www.zdnet.com/article/programming-language-popularity-javascript-leads-5-million-new-developers-since-2017/](https://www.zdnet.com/article/programming-language-popularity-javascript-leads-5-million-new-developers-since-2017/)
   1. 
[https://medium.com/@ApacheAPISIX/why-apache-apisix-chose-nginx-and-lua-to-build-api-gateway-3d4f81e3e1f1](https://medium.com/@ApacheAPISIX/why-apache-apisix-chose-nginx-and-lua-to-build-api-gateway-3d4f81e3e1f1)
   1. 
[https://medium.com/@ApacheAPISIX/how-to-write-an-apache-apisix-plugin-in-java-3fb7b75444fa](https://medium.com/@ApacheAPISIX/how-to-write-an-apache-apisix-plugin-in-java-3fb7b75444fa)
   1. [https://deno.com/blog/v1](https://deno.com/blog/v1)
   1. 
[https://www.youtube.com/watch?v=M3BM9TB-8yA](https://www.youtube.com/watch?v=M3BM9TB-8yA)
   1. 
[https://github.com/second-state/wasm32-wasi-benchmark](https://github.com/second-state/wasm32-wasi-benchmark)
   1. 
[https://www.fastly.com/blog/how-lucet-wasmtime-make-stronger-compiler-together](https://www.fastly.com/blog/how-lucet-wasmtime-make-stronger-compiler-together)
   
   
   What do you think about this? Is the direction I am doing right?
   
   ### Environment
   
   apisix version (cmd: `apisix version`): 2.9


-- 
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]


Reply via email to