Make Your NGINX Config Even More Modular and Reusable with njs 0.7.7

NGINX | October 20, 2022


Since introducing the NGINX JavaScript module (njs) in 2015 (under its original name, nginScript) and making it generally available in 2017<.htmla>, 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:

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:

  1. To someone reading through the configuration, the declarations in the http and stream contexts are essentially noise, because there’s no indication where the associated code and variables are actually used.
  2. It’s not obvious in the child context where the code and variables have been imported and declared. Though we recommend including the http{} and stream{} blocks only in the main configuration file (nginx.conf) and using the include 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 include http{} and stream{} 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:

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).

Loading gist…

Loading gist…

In njs 0.7.7 and later, all the configuration related to the util function is in the one file, jscode_integrated.conf:

Loading gist…

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:

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() and write() 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):

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.


Share

Related Blog Posts

Automating Certificate Management in a Kubernetes Environment
NGINX | 10/05/2022

Automating Certificate Management in a Kubernetes Environment

Simplify cert management by providing unique, automatically renewed and updated certificates to your endpoints.

Secure Your API Gateway with NGINX App Protect WAF
NGINX | 05/26/2022

Secure Your API Gateway with NGINX App Protect WAF

As monoliths move to microservices, applications are developed faster than ever. Speed is necessary to stay competitive and APIs sit at the front of these rapid modernization efforts. But the popularity of APIs for application modernization has significant implications for app security.

How Do I Choose? API Gateway vs. Ingress Controller vs. Service Mesh
NGINX | 12/09/2021

How Do I Choose? API Gateway vs. Ingress Controller vs. Service Mesh

When you need an API gateway in Kubernetes, how do you choose among API gateway vs. Ingress controller vs. service mesh? We guide you through the decision, with sample scenarios for north-south and east-west API traffic, plus use cases where an API gateway is the right tool.

Deploying NGINX as an API Gateway, Part 2: Protecting Backend Services
NGINX | 01/20/2021

Deploying NGINX as an API Gateway, Part 2: Protecting Backend Services

In the second post in our API gateway series, Liam shows you how to batten down the hatches on your API services. You can use rate limiting, access restrictions, request size limits, and request body validation to frustrate illegitimate or overly burdensome requests.

New Joomla Exploit CVE-2015-8562
NGINX | 12/15/2015

New Joomla Exploit CVE-2015-8562

Read about the new zero day exploit in Joomla and see the NGINX configuration for how to apply a fix in NGINX or NGINX Plus.

Why Do I See “Welcome to nginx!” on My Favorite Website?
NGINX | 01/01/2014

Why Do I See “Welcome to nginx!” on My Favorite Website?

The ‘Welcome to NGINX!’ page is presented when NGINX web server software is installed on a computer but has not finished configuring

Deliver and Secure Every App
F5 application delivery and security solutions are built to ensure that every app and API deployed anywhere is fast, available, and secure. Learn how we can partner to deliver exceptional experiences every time.
Connect With Us