Code Examples

Practical snippets for the APM Node.js connector. More languages coming.

Custom response headers

Use the _headers key inside the second argument of conn.write() to attach arbitrary HTTP response headers. Any key inside _headers is forwarded verbatim to the HTTP response.

Common mistake — customHeaders does nothing. The APM Go server reads a special key called _headers (underscore prefix). A top-level key named customHeaders containing a nested object is silently ignored because the server only unpacks string-valued top-level keys and the dedicated _headers sub-object.

Wrong — customHeaders is silently dropped

JavaScript
// ✗ customHeaders is NOT a recognised key — the Go server ignores it
conn.write(html, {
  customHeaders: {
    'Cache-Control': 'no-store',
    'X-My-Header':   'value',
  },
});

Correct — use _headers

JavaScript
// ✓ _headers is the recognised key — every string value becomes a response header
conn.write(html, {
  _headers: {
    'Cache-Control': 'no-store, no-cache',
    'X-My-Header':   'value',
  },
});
How it works. conn.write(data, opts) spreads opts into the IPC frame: {"_command":"write", ...opts}. The Go server iterates the frame, skips underscore-prefixed keys (internal protocol fields), and for the special key _headers it unpacks the nested object and writes each entry as an HTTP response header.

Setting cookies

Cookies are set via Set-Cookie inside _headers — exactly like any other response header. This only works on HTTP connections; on WebSocket connections the HTTP handshake is already complete by the time your handler runs, so Set-Cookie in conn.write() has no effect.

JavaScript
function handleRequest(conn) {
  if (conn.protocol !== 'http') return; // WS: handshake already done

  const cookieName  = 'session';
  const cookieValue = generateToken();
  const cookieStr   = [
    `${cookieName}=${cookieValue}`,
    'Path=/',
    'HttpOnly',
    'SameSite=Strict',
    /* 'Secure' — add when behind HTTPS */
  ].join('; ');

  conn.write(html, {
    _headers: { 'Set-Cookie': cookieStr },
  });
}
To set multiple cookies in one response, the HTTP spec allows repeating the header. APM currently forwards a single string value per header key. Work around this by combining attributes into one Set-Cookie value, or by serving a redirect through a second request that sets additional cookies.

Status codes

Pass _status (a number) alongside _headers to control the HTTP response status code. The default is 200.

JavaScript
// 404 Not Found
conn.write('<h1>Not found</h1>', { _status: 404 });

// 301 redirect
conn.write('', {
  _status: 301,
  _headers: { 'Location': '/new-path' },
});

// 200 with custom content-type and cache header
conn.write(jsonString, {
  _status: 200,
  _headers: {
    'Content-Type':  'application/json',
    'Cache-Control': 'max-age=60',
  },
});

Reading cookies

APM parses the incoming Cookie header for you. Use conn.cookies (an object keyed by cookie name) or conn.headers.cookie (the raw string) on both HTTP and WebSocket connections.

JavaScript
function handleRequest(conn) {
  // conn.cookies is pre-parsed: { session: 'abc123', theme: 'dark', ... }
  const sessionId = conn.cookies['session'];

  if (!sessionId) {
    // No session cookie — send login page
    conn.write(loginPage, { _status: 401 });
    return;
  }

  // Validate sessionId against your store...
  const user = sessions.get(sessionId);
  if (!user) {
    conn.write(loginPage, { _status: 401 });
    return;
  }

  conn.write(dashboardPage(user));
}
conn.cookies is available on both HTTP (conn.protocol === 'http') and WebSocket (conn.protocol === 'ws') connections — APM parses the cookie header from the initial HTTP upgrade request and attaches it to the session object.