Make Your NGINX Config Even More Modular and Reusable with njs 0.7.7
Since introducing the NGINX JavaScript module (njs) in 2015 (under its original name, nginScript) and making it generally available in 2017, we have steadily continued to add new features and refine our implementation across dozens of version updates. Normally we wait for an NGINX Plus release to discuss the features in a new NGINX JavaScript version, but we’re so excited about version 0.7.7 that this time we can’t wait!
The significant enhancements in njs 0.7.7 help make your NGINX configuration even more modular, organized, and reusable:
- You can now declare njs code in the contexts where it applies rather than globally, bringing your custom code closer to the point of usage.
- Hooks in the njs code itself enable you to modify behavior depending on the execution context.
- The new
fs.FileHandle
object makes file operations more efficient.
To learn more about njs and review the list of use cases for which we provide sample code, read Harnessing the Power and Convenience of JavaScript for Each Request with the NGINX JavaScript Module on our blog.
For a complete list of all new features and bug fixes in njs 0.7.7, see the Changes documentation.
Declaring JavaScript Code and Variables in Local Contexts
In previous njs versions, you have to import your JavaScript code and declare the relevant variables – with the js_import
, js_path
, js_set
, and js_var
directives – in the top‑level http
or stream
context, the equivalent of declaring global variables at the top of a main file. But the directives that actually invoke the JavaScript functions and variables appear in a child context – for example, with the js_content
directive in an HTTP location{}
block and the js_access
directive in a Stream server{}
block. This creates two issues:
- To someone reading through the configuration, the declarations in the
http
andstream
contexts are essentially noise, because there’s no indication where the associated code and variables are actually used. - It’s not obvious in the child context where the code and variables have been imported and declared. Though we recommend including the
http{}
andstream{}
blocks only in the main configuration file (nginx.conf) and using theinclude
directive to read in smaller function‑specific configuration files from the /etc/nginx/conf.d and /etc/nginx/stream.d directories, NGINX configuration is flexible – you can includehttp{}
andstream{}
blocks in multiple files. This can be especially problematic in environments where multiple people work on your NGINX configuration and might not always follow established conventions.
In njs 0.7.7 and later, you can import code and declare variables in the contexts where they’re used:
-
HTTP –
-
Stream –These directives can appear in the
server
context as well as thestream
context:
Having all njs configuration for a specific use case in a single file also makes your code more modular and portable.
As an example, in previous njs versions when you added a new script you had to change both nginx.conf (adding js_import
and possibly js_path
, js_set
, and js_var
) and the file where the JavaScript function is invoked (here, jscode_local.conf).
In njs 0.7.7 and later, all the configuration related to the util function is in the one file, jscode_integrated.conf:
Modifying Behavior Depending on the Execution Context
Several new features in njs 0.7.7 enable you to modify the behavior of your JavaScript code depending on the context (processing phase) where it is executing.
The HTTP r.internal
Property
The HTTP r.internal
property is a Boolean flag set to “true” for internal requests (which are handled by location{}
blocks that include the internal
directive). You can use the r.internal
flag to fork logic when a script uses a general event handler that can be called in both internal and non‑internal contexts.
The following classify as internal requests:
- Requests redirected by the
error_page
,index
,random_index
, andtry_files
directives - Requests redirected by the
X-Accel-Redirect
response header from an upstream server - Subrequests invoked by the
auth_request
andmirror
directives, the directives in the ngx_http_addition_module module, or the Server Side Include (SSI)include
virtual
command (supported by the ngx_http_ssi_module module) - Requests changed by the
rewrite
directive
Improved s.send()
Stream Method
In earlier njs versions, the Stream s.send()
method is context‑dependent, because the direction in which it sends data is determined by the location (upstream or downstream) of the callback where the method is called. This works fine for synchronous callbacks – which s.send()
was originally designed for – but fails with asynchronous functions such as ngx.fetch()
.
In njs 0.7.7 and later, the direction is stored in a separate internal flag, which s.send()
can then use.
More Efficient File Operations with the New fs.FileHandle()
Object
The file system module (fs
) implements operations on files. The new FileHandle
object in the fs
module is an object wrapper for a numeric file descriptor. Instances of the FileHandle
object are created by the fs.promises.open()
method.
Use the FileHandle
object to get a file descriptor, which can be further used to:
- Perform functions like
read()
andwrite()
on the file - Open a file and perform reads and writes at a specified location without reading the whole file
The following properties of FileHandle
have been implemented (for information about the required and optional arguments for each property, see the documentation):
filehandle.fd
filehandle.read()
filehandle.stat()
filehandle.write()
filehandle.write()
filehandle.close()
These methods have been updated to support FileHandle
(see the linked documentation for information about each method’s arguments):
fs.openSync()
fs.promises.open()
fs.fstatSync()
fs.readSync()
fs.writeSync()
(buffer)fs.writeSync()
(string)
Use njs to Enhance Your Configuration
With njs 0.7.7, we’ve made it easier for your teams to work on and share njs code. The extended contexts for njs directives make it even more straightforward to enhance NGINX configuration with custom JavaScript code. You can make the first move towards an API gateway, reverse proxy, or web server – and one that is more than just another middleware or edge component. You can make it part of your application through JavaScript, TypeScript, or third‑party node modules without adding another component in your stack. All you need is NGINX!
Have questions? Join the NGINX Community Slack and check out the #njs-code-review channel to learn more, ask questions, and get feedback on your njs code.
The post Make Your NGINX Config Even More Modular and Reusable with njs 0.7.7 appeared first on NGINX.
Source: Make Your NGINX Config Even More Modular and Reusable with njs 0.7.7
Leave a Reply