Skip to content

Commit

Permalink
feat: route accroding to the graphql attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
spacewander committed Dec 7, 2020
1 parent c41aa85 commit 9a14974
Show file tree
Hide file tree
Showing 9 changed files with 457 additions and 20 deletions.
1 change: 1 addition & 0 deletions apisix/cli/env.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ return function (apisix_home, pkg_cpath_org, pkg_path_org)
.. apisix_home .. "/deps/lib/lua/5.1/?.so;"

local pkg_path = apisix_home .. "/?/init.lua;"
.. apisix_home .. "/deps/share/lua/5.1/?/init.lua;"
.. apisix_home .. "/deps/share/lua/5.1/?.lua;;"

package.cpath = pkg_cpath .. package.cpath
Expand Down
80 changes: 79 additions & 1 deletion apisix/core/ctx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,96 @@
-- limitations under the License.
--
local core_str = require("apisix.core.string")
local core_tab = require("apisix.core.table")
local request = require("apisix.core.request")
local log = require("apisix.core.log")
local config_local = require("apisix.core.config_local")
local tablepool = require("tablepool")
local get_var = require("resty.ngxvar").fetch
local get_request = require("resty.ngxvar").request
local ck = require "resty.cookie"
local gq_parse = require("graphql").parse
local setmetatable = setmetatable
local sub_str = string.sub
local rawset = rawset
local ngx = ngx
local ngx_var = ngx.var
local re_gsub = ngx.re.gsub
local ipairs = ipairs
local type = type
local error = error
local ngx = ngx
local pcall = pcall


local _M = {version = 0.2}
local GRAPHQL_DEFAULT_MAX_SIZE = 1048576 -- 1MiB


local function parse_graphql(ctx)
local local_conf, err = config_local.local_conf()
if not local_conf then
return nil, "failed to get local conf: " .. err
end

local max_size = GRAPHQL_DEFAULT_MAX_SIZE
local size = core_tab.try_read_attr(local_conf, "graphql", "max_size")
if size then
max_size = size
end

local body, err = request.get_body(max_size, ctx)
if not body then
return nil, "failed to read graphql body: " .. err
end

local ok, res = pcall(gq_parse, body)
if not ok then
return nil, "failed to parse graphql: " .. res .. " body: " .. body
end

if #res.definitions == 0 then
return nil, "empty graphql: " .. body
end

return res, nil
end


local function get_parsed_graphql(ctx)
if not ctx._graphql then
local res, err = parse_graphql(ctx)
if not res then
log.error(err)
ctx._graphql = {}

else
if #res.definitions > 1 then
log.warn("Mutliple operations are not supported.",
"Only the first one is handled")
end

local def = res.definitions[1]
local fields = def.selectionSet.selections
local root_fields = core_tab.new(#fields, 0)
for i, f in ipairs(fields) do
root_fields[i] = f.name.value
end

local name = ""
if def.name and def.name.value then
name = def.name.value
end

ctx._graphql = {
name = name,
operation = def.operation,
root_fields = root_fields,
}
end
end

return ctx._graphql
end


do
Expand Down Expand Up @@ -84,6 +158,10 @@ do
key = re_gsub(key, "-", "_", "jo")
val = get_var(key, t._request)

elseif core_str.has_prefix(key, "graphql_") then
key = sub_str(key, 9)
val = get_parsed_graphql(t)[key]

elseif key == "route_id" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.route_id

Expand Down
4 changes: 4 additions & 0 deletions conf/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ apisix:
key_encrypt_salt: "edd1c9f0985e76a2" # If not set, will save origin ssl key into etcd.
# If set this, must be a string of length 16. And it will encrypt ssl key with AES-128-CBC
# !!! So do not change it after saving your ssl, it can't decrypt the ssl keys have be saved if you change !!

nginx_config: # config for render the template to genarate nginx.conf
error_log: "logs/error.log"
error_log_level: "warn" # warn,error
Expand Down Expand Up @@ -195,6 +196,9 @@ etcd:
# send: 2000 # default 2000ms
# read: 5000 # default 5000ms

graphql:
max_size: 1048576 # the maximum size limitation of graphql in bytes, defualt 1MiB

plugins: # plugin list (sorted in alphabetical order)
- api-breaker
- authz-keycloak
Expand Down
55 changes: 55 additions & 0 deletions doc/router-radixtree.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,58 @@ $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f
```

This route will require the request header `host` equal `iresty.com`, request cookie key `_device_id` equal `a66f0cdc4ba2df8c096f74c9110163a9` etc.

### How to filter route by graphql attributes

APISIX supports filtering route by some attributes of graphql. Currently we support:

* graphql_operation
* graphql_name
* graphql_root_fields

For instance, with graphql like this:
```graphql
query getRepo {
owner {
name
}
repo {
created
}
}
```

* The `graphql_operation` is `query`
* The `graphql_name` is `getRepo`,
* The `graphql_root_fields` is `["owner", "repo"]`

We can filter such route out with:
```shell
$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/_graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo"],
["graphql_root_fields", "has", "owner"]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
```

To prevent spending too much time reading invalid graphql request body, we only read the first 1 MiB
data from the request body. This limitation is configured via:

```yaml
graphql:
max_size: 1048576

```

If you need to pass a graphql body which is larger than the limitation, you can increase the value in `conf/config.yaml`.
1 change: 1 addition & 0 deletions rockspec/apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ dependencies = {
"dkjson = 2.5-2",
"resty-redis-cluster = 1.02-4",
"lua-resty-expr = 1.0.0",
"graphql = 0.0.2",
}

build = {
Expand Down
12 changes: 7 additions & 5 deletions t/APISIX.pm
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ add_block_preprocessor(sub {
my ($block) = @_;
my $wait_etcd_sync = $block->wait_etcd_sync // 0.1;

my $lua_deps_path = <<_EOC_;
lua_package_path "$apisix_home/?.lua;$apisix_home/?/init.lua;$apisix_home/deps/share/lua/5.1/?/init.lua;$apisix_home/deps/share/lua/5.1/?.lua;$apisix_home/apisix/?.lua;$apisix_home/t/?.lua;;";
lua_package_cpath "$apisix_home/?.so;$apisix_home/deps/lib/lua/5.1/?.so;$apisix_home/deps/lib64/lua/5.1/?.so;;";
_EOC_

my $main_config = $block->main_config // <<_EOC_;
worker_rlimit_core 500M;
env ENABLE_ETCD_AUTH;
Expand All @@ -150,9 +155,7 @@ _EOC_

my $stream_enable = $block->stream_enable;
my $stream_config = $block->stream_config // <<_EOC_;
lua_package_path "$apisix_home/?.lua;$apisix_home/?/init.lua;$apisix_home/deps/share/lua/5.1/?.lua;$apisix_home/apisix/?.lua;$apisix_home/t/?.lua;;";
lua_package_cpath "$apisix_home/?.so;$apisix_home/deps/lib/lua/5.1/?.so;$apisix_home/deps/lib64/lua/5.1/?.so;;";
$lua_deps_path
lua_socket_log_errors off;
lua_shared_dict lrucache-lock-stream 10m;
Expand Down Expand Up @@ -232,8 +235,7 @@ _EOC_

my $http_config = $block->http_config // '';
$http_config .= <<_EOC_;
lua_package_path "$apisix_home/?.lua;$apisix_home/?/init.lua;$apisix_home/deps/share/lua/5.1/?.lua;$apisix_home/apisix/?.lua;$apisix_home/t/?.lua;;";
lua_package_cpath "$apisix_home/?.so;$apisix_home/deps/lib/lua/5.1/?.so;$apisix_home/deps/lib64/lua/5.1/?.so;;";
$lua_deps_path
lua_shared_dict plugin-limit-req 10m;
lua_shared_dict plugin-limit-count 10m;
Expand Down
5 changes: 3 additions & 2 deletions t/lib/test_admin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,15 @@ function _M.comp_tab(left_tab, right_tab)
local err
dir_names = {}

local _
if type(left_tab) == "string" then
left_tab, err = json.decode(left_tab)
left_tab, _, err = json.decode(left_tab)
if not left_tab then
return false, "failed to decode expected data: " .. err
end
end
if type(right_tab) == "string" then
right_tab, err = json.decode(right_tab)
right_tab, _, err = json.decode(right_tab)
if not right_tab then
return false, "failed to decode expected data: " .. err
end
Expand Down
22 changes: 10 additions & 12 deletions t/plugin/openid-connect.t
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,7 @@ WWW-Authenticate: Bearer realm=apisix
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
[[{ "plugins": {
"openid-connect": {
"client_id": "kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
"client_secret": "60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa",
Expand All @@ -294,10 +293,10 @@ WWW-Authenticate: Bearer realm=apisix
"timeout": 10,
"bearer_only": true,
"scope": "apisix",
"public_key": "-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANW16kX5SMrMa2t7F2R1w6Bk/qpjS4QQ
hnrbED3Dpsl9JXAx90MYsIWp51hBxJSE/EPVK8WF/sjHK1xQbEuDfEECAwEAAQ==
-----END PUBLIC KEY-----",
"public_key": "-----BEGIN PUBLIC KEY-----\n]] ..
[[MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANW16kX5SMrMa2t7F2R1w6Bk/qpjS4QQ\n]] ..
[[hnrbED3Dpsl9JXAx90MYsIWp51hBxJSE/EPVK8WF/sjHK1xQbEuDfEECAwEAAQ==\n]] ..
[[-----END PUBLIC KEY-----",
"token_signing_alg_values_expected": "RS256"
}
},
Expand All @@ -309,8 +308,7 @@ hnrbED3Dpsl9JXAx90MYsIWp51hBxJSE/EPVK8WF/sjHK1xQbEuDfEECAwEAAQ==
},
"uri": "/hello"
}]],
[[{
"node": {
[[{ "node": {
"value": {
"plugins": {
"openid-connect": {
Expand All @@ -322,10 +320,10 @@ hnrbED3Dpsl9JXAx90MYsIWp51hBxJSE/EPVK8WF/sjHK1xQbEuDfEECAwEAAQ==
"timeout": 10000,
"bearer_only": true,
"scope": "apisix",
"public_key": "-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANW16kX5SMrMa2t7F2R1w6Bk/qpjS4QQ
hnrbED3Dpsl9JXAx90MYsIWp51hBxJSE/EPVK8WF/sjHK1xQbEuDfEECAwEAAQ==
-----END PUBLIC KEY-----",
"public_key": "-----BEGIN PUBLIC KEY-----\n]] ..
[[MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANW16kX5SMrMa2t7F2R1w6Bk/qpjS4QQ\n]] ..
[[hnrbED3Dpsl9JXAx90MYsIWp51hBxJSE/EPVK8WF/sjHK1xQbEuDfEECAwEAAQ==\n]] ..
[[-----END PUBLIC KEY-----",
"token_signing_alg_values_expected": "RS256"
}
},
Expand Down
Loading

0 comments on commit 9a14974

Please sign in to comment.