Apache APISIX supports plug-in writing in multiple languages! It doesn’t matter if you don’t know Lua, you can now write plugins in languages you’re familiar with. Check out the website for videos and tutorials.

1. Introduction

1.1 Why Does Apache APISIX support writing plug-ins in multiple languages

Before supporting multi-language plug-ins, Apache APISIX only supports plug-ins written in Lua, which requires developers to master Lua and OpenResty development capabilities. However, compared to the mainstream development languages Java and Go, Lua and OpenResty are relatively niche technologies with few developers. Learning Lua and OpenResty from scratch takes a considerable amount of time and effort.

When choosing technologies, the most important consideration for the development team is whether the selected technologies match the team’s technology stack. However, the small technology stack limits the implementation of Apache APISIX in a broader scenario.

Apache APISIX now supports plug-in development in multiple languages and, more importantly, in the development ecosystem of the languages, allowing users to develop Apache APISIX using their familiar technology stack. Java support, for example, allows users not only to write plug-ins in the Java language, but also to integrate into the Spring Cloud ecosystem and use a wide range of technology components within the ecosystem.

1.2 Apache APISIX multi-language support architecture diagram

The figure above shows the Apache APISIX workflow on the left, and the Plugin Runner on the right refers to the plug-in runner, which generally refers to multi-language supported projects. The Apisix-java-plugin-Runner project mentioned below in this document is a Plugin Runner that supports the Java language.

When you configure a Plugin Runner in Apache APISIX, Apache APISIX will start a child process running the Plugin Runner, which belongs to the same user as the Apache APISIX process. Plugin Runner will also be restarted when we restart or reload Apache APISIX.

If you configure the ext-plugin-* plug-in for a given route, a request hitting the route will trigger Apache APISIX to execute an RPC call to the Plugin Runner through the Unix socket. The call is subdivided into two phases:

  • Ext-plugin-pre-req: Before executing the Apache APISIX built-in plugin (Lua language plugin)
  • Ext-plugin-post-req: After executing the Apache APISIX built-in plug-in (Lua language plug-in)

Configure the execution time of plugin Runner as required.

The Plugin Runner processes the RPC call, creates a mock request inside it, then runs the plug-in written in multiple languages, and returns the results to Apache APISIX.

The order of execution for multi-language plug-ins is defined in the ext-plugin-* plug-in configuration item. Like other plug-ins, they can be enabled and redefined on the fly.

2. Set up the development environment

First, you need to build the Apache APISIX running environment or development environment, refer to building Apache APISIX, and Java project development environment, refer to building Apisix-java-plugin-runner. Note: Apache APISIX and apisix-java-plugin-runner need to be on the same instance.

3. Enter the debugging mode

3.1 Setting Apache APISIX to The Debug Mode

Let Apache APISIX run the external plug-in in debug mode by adding the following configuration in config.yaml

ext-plugin:
  path_for_test: /tmp/runner.sock
Copy the code

This configuration means that Apache APISIX acts as a client and listens for the Unxi Domain Socket connection at the/TMP /runner. Sock location.

3.2 Setting apisix-java-plugin-runner to the debugging mode

Start in the Main class (org. Apache. Apisix. Plugin. Runner. PluginRunnerApplication) before, Configure the user-level environment variables APISIX_LISTEN_ADDRESS= Unix :/ TMP /runner. Sock and APISIX_CONF_EXPIRE_TIME=3600.

If you are developing with IDEA, the configured environment variables look like this:

Apisix-java-plugin-runner is equivalent to the server side. When the server starts, it will actively create/TMP /runner. Sock file and use this file to communicate with Apache Apisix Unix Domain Socket.

Development of 4.

4.1 scenario

We substitute a scenario into the development process: we need to verify the validity of the token in the request header. The token authentication method is to use the token in the request as a parameter to access the fixed interface of SSO. If the token authentication passes, the request is allowed; if the authentication fails, the request is blocked.

4.2 Configuring Apache APISIX

Name the plug-in TokenValidator, and then design the properties, which are designed to be as dynamic as possible

{
  "validate_header": "token",
  "validate_url": "https://www.sso.foo.com/token/validate",
  "rejected_code": "403"
}
Copy the code

Start Apache APISIX and add a route configuration specifying that the route calls the TokenValidator plug-in of apisix-java-plugin-runner as shown in the following example

The curl http://127.0.0.1:9080/apisix/admin/routes/1 - H 'X - API - KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri":"/get", "plugins":{ "ext-plugin-pre-req":{ "conf":[ { "name":"TokenValidator", "value":"{\"validate_header\":\"token\",\"validate_url\":\"https://www.sso.foo.com/token/validate\",\"rejected_code\":\" 403\"}" } ] } }, "upstream":{ "nodes":{ "httpbin.org:80":1 }, "type":"roundrobin" } }Copy the code

Note that the properties of the TokenValidator need to be escaped by JSON and configured as strings.

(The upstream address is httpbin.org for debugging purposes)

4.3 Java Plug-in development

The runner – the plugin/SRC/main/Java/org/apache/apisix/plugins/runner/filter directory, new TokenValidatr. Java, initial skeleton code is as follows

package org.apache.apisix.plugin.runner.filter;

import org.apache.apisix.plugin.runner.HttpRequest;
import org.apache.apisix.plugin.runner.HttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;


@Component
public class TokenValidator implements PluginFilter {

    @Override
    public String name(a) {
        return "TokenValidator";
    }

    @Override
    public Mono<Void> filter(HttpRequest request, HttpResponse response, PluginFilterChain chain) {
        returnchain.filter(request, response); }}Copy the code

You need to inherit from the PluginFilter interface, overriding the name and filter functions.

Overwrite the return value of name to be the same as “name” in the route attribute configured with APISIX.

The complete code is as follows:

package org.apache.apisix.plugin.runner.filter;

import com.google.gson.Gson;
import org.apache.apisix.plugin.runner.HttpRequest;
import org.apache.apisix.plugin.runner.HttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

@Component
public class TokenValidator implements PluginFilter {

    @Override
    public String name(a) {
        return "TokenValidator";
    }

    @Override
    public Mono<Void> filter(HttpRequest request, HttpResponse response, PluginFilterChain chain) {
        // parse `conf` to json
        String configStr = request.getConfig(this);
        Gson gson = new Gson();
        Map<String, Object> conf = new HashMap<>();
        conf = gson.fromJson(configStr, conf.getClass());

        // get configuration parameters
        String token = request.getHeader((String) conf.get("validate_header"));
        String validate_url = (String) conf.get("validate_url");
        boolean flag = validate(token, validate_url);

        // token verification results
        if(! flag) { String rejected_code = (String) conf.get("rejected_code");
            response.setStatusCode(Integer.parseInt(rejected_code));
            return chain.filter(request, response);
        }

        return chain.filter(request, response);
    }

    private Boolean validate(String token, String validate_url) {
        //TODO: improve the validation process
        return true; }}Copy the code

4.4 test

The upstream service configured on Apache APISIX is httpbin.org, which can access Apache APISIX, trigger routing, Let Apache APISIX call apisix-java-plugin-runner to execute the TokenValidator plug-in to test the effect of the Java plug-in.

Curl -h 'token: 123456' 127.0.0.1:9080 / get {" args ": {}," headers ": {" Accept" : "/", "the Host" : "127.0.0.1", "token" : "123456", "the user-agent" : "curl / 7.71.1", "X - Amzn - Trace - Id" : "Root= 1-60CB0424-02b5BF804CFEAB525239f96 ", "x-forwarded-host ": "127.0.0.1"}, "origin": "127.0.0.1", "url": "Http://127.0.0.1/get"}Copy the code

Deployment of 5.

For details about how to deploy the plug-in, see Deploying apisix-java-plugin-Runner.

Video tutorials

Check out the video tutorial on the website

Follow the public account to read the latest technical articles.