Closed fhirfly closed 3 years ago
njs doesn’t support async/await yet. However, async/await is just a syntactic sugar for Promises, which njs does support. So you can just use Promise (API is basically the same as in Node.js or browsers).
Or if you really want async/await syntax, you can transpile your code using Babel and babel-plugin-transform-async-to-promises.
See also babel-preset-njs and njs-typescript-starter.
@fhirfly
You are having troubles with js_set
, which is completely synchronous, so you can't wait for subrequest response inside its handler.
Any ideas on a workaround if the nginx wont wait on the njs function?
js_var $xxx;
server {
listen 10000;
location = /generate_some_token {
return 200 "hereisthetoken";
}
location = /protected_api_endpoint {
js_content test.protected_api_endpoint;
}
location = /proxy_to_api_endpoint {
proxy_set_header xxx "$xxx";
proxy_pass http://127.0.0.1:10000/protected_api_endpoint;
}
location = /entry_point {
js_content test.entry_point;
}
function protected_api_endpoint(r) {
r.return(200, r.headersIn['xxx'] ? `Hello [${r.headersIn['xxx']}]!` : 'Bad Luck');
}
function entry_point(r) {
r.subrequest('/generate_some_token')
.then((res) => {
r.variables['xxx'] = res.responseBody;
r.internalRedirect('/proxy_to_api_endpoint');
})
.catch((e) => { r.error(e.message); r.return(500); });
}
$ curl http://127.0.0.1:10000/entry_point
Hello [hereisthetoken]!
So I tested the above theory and it works. The only issue with this code is that there is a 1:1:1 between /entrypoint, function entry_point, and /proxy_to_api_endpoint . Some of my configuration have many endpoints and I would like to reuse some of the code and not have a unmaintainable mess. Does the r.variable have the path of the original request or is there some other variable I can use in the internalredirect or in /proxy_to_api_endpoint to make this dynamic? My proxy doesn't rewrite the path, there is a constant relationship between the nginx gateway URL and the google api url . E.g, /Endpoint on the proxy passes to https://healthcare.googleapis.com/v1beta1/projects/projectname/locations/wherever/datasets/ds/fhirStores/sn/fhir/Endpoint, and the part before /Endpoint on the google side is constant. Thanks for the work around.
@fhirfly $request_uri does not get rewritten (https://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri).
location = /proxy_to_api_endpoint {
#proxy_set_header xxx "$xxx";
#proxy_pass http://127.0.0.1:10000/protected_api_endpoint;
add_header xxx $xxx;
return 200 $request_uri;
}
# curl -vvv http://127.0.0.1/entry_point
...
< HTTP/1.1 200 OK
< Server: nginx/1.21.0
< Date: Fri, 04 Jun 2021 12:09:54 GMT
< Content-Type: application/octet-stream
< Content-Length: 12
< Connection: keep-alive
< xxx: hereisthetoken
<
* Connection #0 to host 127.0.0.1 left intact
/entry_point
@fhirfly
js_var $auth;
server {
resolver 1.1.1.1 ipv6=off;
listen 10000;
location = /auth_token {
internal;
return 200 "hereisthetoken";
}
location = /auth_pass {
internal;
proxy_set_header auth "$auth";
proxy_pass http://127.0.0.1:10000/protected_api_endpoint$request_uri;
}
location / {
js_content test.entry_point;
}
#google
location /protected_api_endpoint {
js_content test.protected_api_endpoint;
}
}
function protected_api_endpoint(r) {
r.return(200, r.headersIn['auth'] ? `Hello [auth: ${r.headersIn['auth']}][uri: ${r.uri}]!\n` : 'Bad Luck\n');
}
function entry_point(r) {
r.subrequest('/auth_token')
.then((res) => {
r.variables['auth'] = res.responseText;
r.internalRedirect('/auth_pass');
})
.catch((e) => { r.error(e.message); r.return(500);});
}
$ curl http://127.0.0.1:10000/
Hello [auth: hereisthetoken][uri: /protected_api_endpoint/]!
$ curl http://127.0.0.1:10000/one/two/three
Hello [auth: hereisthetoken][uri: /protected_api_endpoint/one/two/three]!
$ curl http://127.0.0.1:10000/one/two/three?four=five
Hello [auth: hereisthetoken][uri: /protected_api_endpoint/one/two/three]!
I have this synchronization issue as described here:
https://stackoverflow.com/questions/67800478/nginx-service-callout-for-an-api-access-token-in-api-gateway-proxy-configuration
I am wondering if maybe it is impossible to wait for the function to return before nginix executes proxypass.
I tried doing async on function getGoogleAccessToken(r) and got the error I put in the issue header.
Any ideas on a workaround if the nginx wont wait on the njs function?
Maybe there is a bug in my code, but the logs seem to indicate this problem as coded.