Node.js Integration Guide

The @ztlayer/node SDK provides high-performance, low-level bindings for securing raw Node.js http and https servers, as well as modern, fast frameworks like Fastify.

If you are using Express, please refer to the dedicated Express Integration Guide.


1. Installation

Install the Node.js SDK:

npm install @ztlayer/node

2. Configuration & Initialization

Set your API key in your environment variables.

# .env
ZTLAYER_API_KEY="zt_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Initialize the SDK singleton. This should be done once during your application's bootstrap phase.

import { ZTLayer } from '@ztlayer/node';
 
const security = new ZTLayer({
  apiKey: process.env.ZTLAYER_API_KEY,
  // Recommended: Set environment so metrics are bucketed correctly
  environment: process.env.NODE_ENV || 'development',
  failMode: 'open' 
});

3. Raw HTTP Server Example

If you are building a lightweight microservice using Node's built-in http module, you can wrap the request handler.

import http from 'http';
 
const server = http.createServer(async (req, res) => {
  try {
    // 1. Inspect the request before routing
    const verdict = await security.inspectHTTP(req);
 
    // 2. Handle the verdict
    if (verdict.action === 'block') {
      res.writeHead(403, { 'Content-Type': 'application/json' });
      return res.end(JSON.stringify({ error: 'Blocked by ZTLayer WAF' }));
    }
 
    if (verdict.action === 'challenge') {
      res.writeHead(401, { 'Content-Type': 'application/json' });
      return res.end(JSON.stringify({ error: 'Challenge Required', url: verdict.challengeUrl }));
    }
 
    // 3. Request is safe. Proceed with your business logic.
    if (req.url === '/api/health') {
      res.writeHead(200);
      return res.end('OK');
    }
    
    res.writeHead(404);
    res.end();
 
  } catch (error) {
    // In fail-open mode, inspectHTTP will rarely throw, but always catch errors globally
    console.error('Security verification failed:', error);
    res.writeHead(500);
    res.end('Internal Server Error');
  }
});
 
server.listen(3000, () => console.log('Secure server running on port 3000'));

4. Fastify Integration

Fastify is supported natively via its plugin architecture. You can register ZTLayer as a pre-handler hook.

import Fastify from 'fastify';
 
const fastify = Fastify({ logger: true });
 
// Register the ZTLayer Hook
fastify.addHook('preHandler', async (request, reply) => {
  const verdict = await security.inspectFastify(request);
  
  if (verdict.action === 'block') {
    // Fastify will automatically halt the request lifecycle
    reply.code(403).send({ error: 'Blocked by ZTLayer' });
    return reply;
  }
});
 
fastify.get('/api/data', async (request, reply) => {
  return { hello: 'world' };
});
 
fastify.listen({ port: 3000 });

Advanced: Excluding Webhooks

If you are receiving Stripe or GitHub webhooks, you may want to bypass the security inspection to avoid accidental blocking of legitimate server-to-server traffic.

fastify.addHook('preHandler', async (request, reply) => {
  // Bypass inspection for specific routes
  if (request.url.startsWith('/api/webhooks/')) {
    return;
  }
  
  const verdict = await security.inspectFastify(request);
  if (verdict.action === 'block') {
    reply.code(403).send({ error: 'Blocked' });
  }
});