About Deploying nodejs applications to Apigee Edge

Hi friends,

I want to talk about deploying and running nodejs applications within Apigee Edge api proxies.

The capability to do this has been available for several years, and is documented here. To make it possible, Apigee built a node runtime on top of the Rhino JavaScript engine for the Java JVM. This runtime is called "trireme".

Nodejs apps are treated as a type of "target endpoint" within Apigee Edge. Rather than an external HTTP Target, or a local target (another API proxy deployed in the same environment), the nodejs app is a node target.

Some of us like to work "online" in the API PRoxy editor. To add a nodejs target to an existing API Proxy, just add a Resource, and select the node type. Write your node code, specify your dependencies, and there ya go.

I'm the other kind of developer - I build things locally, then import them via the administrative API for Apigee Edge. To make that happen, I need to structure my API Proxy in a certain way.

The structure of an API Proxy bundle

First, let's look at the structure of an API Proxy that does not include a nodejs target. Remember that apiproxy bundles must be zipped up, in order to get imported. The zip structure looks like this:

apiproxy/
apiproxy/frontend.xml
apiproxy/policies/
apiproxy/policies/AM-ServiceCalloutUrl.xml
apiproxy/policies/JS-AssignServiceCalloutUrlVariables.xml
apiproxy/policies/KVM-ReadTargetUrl-1.xml
apiproxy/policies/KVM-ReadTargetUrl-2.xml
apiproxy/policies/SC-ToBackend.xml
apiproxy/proxies/
apiproxy/proxies/default.xml
apiproxy/resources/
apiproxy/resources/jsc/
apiproxy/resources/jsc/assignServiceCalloutUrlVariables.js
apiproxy/resources/jsc/messageTemplate.js

This is the actual output of "unzip -l" on a bundle I had previously created. You can see that the top level dir is "apiproxy" and then there are some child directories. This bundle has no targets so you don't see a targets subdirectory. Now let's look at the corresponding output for an apiproxy bundle that contains a nodejs target.

apiproxy/
apiproxy/nodejs-test.xml
apiproxy/policies/
apiproxy/policies/AM-CleanResponseHeaders.xml
apiproxy/policies/AM-ExpiredApiKey.xml
apiproxy/policies/AM-InvalidApiKey.xml
apiproxy/policies/JS-MaybeFormatFault.xml
apiproxy/policies/RF-UnknownRequest.xml
apiproxy/proxies/
apiproxy/proxies/default.xml
apiproxy/resources/
apiproxy/resources/jsc/
apiproxy/resources/jsc/maybeFormatFault.js
apiproxy/resources/node/
apiproxy/resources/node/index.js
apiproxy/resources/node/node_modules.zip
apiproxy/resources/node/package.json
apiproxy/targets/
apiproxy/targets/default.xml

What's new here? Well, first notice that there is a targets subdirectory. The target needs to include a TargetEndpoint that contains a ScriptTarget, which looks like this:

<TargetEndpoint name='default'> 
  <ScriptTarget>
      <ResourceURL>node://index.js</ResourceURL>
      <EnvironmentVariables>
          <EnvironmentVariable name="NAME">VALUE</EnvironmentVariable>
      </EnvironmentVariables>
      <Arguments>
          <Argument>ARG</Argument>
      </Arguments>
  </ScriptTarget>
</TargetEndpoint>

Next, notice that the node code falls under the resources/node directory. The index.js contains the main logic, and the package.json is a standard npm package file specifying the dependencies, among other things. You will also notice the node_modules.zip file. Hmmm..... what's that about?

Three ways to install dependencies

To import an API Proxy that relies on nodejs, you (as operator or proxy author) need to somehow provide the dependencies to Apigee Edge. There are three ways I know of, to do this:

  1. zip up the node_modules directory, and include that in the bundle zip.
  2. zip up the children of the node_modules directory, and upload each one independently as a node resource
  3. run "npm install" remotely via the Edge Administrative API.

The result of the first approach is shown in the output of unzip above. There is a node_modules.zip file, that contains the node_modules/ directory, zipped. This node_modules.zip is included in the apiproxy bundle zip. Import the whole thing, and you can deploy. This is the approach taken by pushapi. It is described in more detail here.

The second approach divides the dependencies into top-level modules uploads them separately. This is the approach taken by the apigeetool.

The third approach does not require you to directly upload the dependencies; instead you run an admin API command to tell Edge to satisfy the dependencies remotely. This is described by this post by Corinna here, and this is also the approach taken by apigee-edge-js (See the importAndDeploy.js example script).

Interestingly, the Powershell module for Apigee Edge (See the Import-EdgeAPI cmdlet) is agnostic. It does not do anything special for the node resources. So for now (pending a modification to that module) you need to choose one of the above to make the right thing happen.

OK, those are the three ways; how do you choose? I dunno! I don't know which is preferable. Use whichever makes sense to you.

A Caveat - Trireme is not current nodejs

While Trireme is an impressive bit of magic, unfortunately the combination of Rhino and trireme has not kept pace with the development of nodejs in general. Node v6 and beyond supports ES6, as well as a number of other advancements, but Trireme offers node v0.10.32. This means that you cannot use native promises, and you cannot use current modules that rely on ES6 structures like let and const, or the => arrow function notation.

What can you do?

Soon, Apigee will release native nodejs capability for Apigee Edge. This will allow you to include nodejs scripts into your API Proxies, that rely on the latest node engine. It will run on "real" node, using v8, and you will be able to specify the node engine version. Your code and the code of dependencies will be able to use ES6 capabilities including let, const, and arrow functions.

To find out more about getting access to that capability, post a comment here.

Comments
Not applicable

I'd be interested in the native support - especially for my class that starts in January

Version history
Last update:
‎11-27-2017 12:31 PM
Updated by: