A library aiming to provide Node.js-compatible request and response objects.
Compute provides Request and Response objects based on the modern Fetch standard rather than the req and res objects traditionally seen in Node.js programs. If you are more familiar with using the Node.js request and response objects, or have some libraries that work with them, this library aims to let you do that.
To your Compute JavaScript project (which you can create using npm init @fastly/create and the Compute JavaScript Empty Starter Kit), add the @fastly/http-compute-js package as a dependency.
npm install @fastly/http-compute-js
In your program:
import http from '@fastly/http-compute-js';
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!'
  }));
});
server.listen();req and res are implementations of IncomingMessage and ServerResponse, respectively, and can be used as in a Node.js program.
req is an IncomingMessage object whose Readable interface has been wired to the body of the Compute request's body stream. As such, you can read from it using the standard on('data')/on('end') mechanisms, or using libraries such as parse-body. You can also read the headers and other information using the standard interface.
res is a ServerResponse object whose Writable interface is wired to an in-memory buffer. Write to it normally using res.write() / res.end() or pipe to it using res.pipe(). You can also set headers and status code using the standard interfaces.
- The aim of this library is to provide compatibility where practical. Please understand that some features are not possible to achieve 100% compatibility with Node.js, due to platform differences.
- The library uses npm packages such as stream-browserify, buffer, events, and process to simulate Node.js behavior for low-level objects.
- Other libraries that consume IncomingMessageandServerResponsemay or may not be compatible with Compute. Some may work if you apply polyfills during module bundling.
- HTTP Version is currently always reported as 1.1.
- Unlike in Node.js, the socketproperty of these objects is alwaysnull, and cannot be assigned.
- Some functionality is not (yet) supported: http.Agent,http.ClientRequest,http.get(),http.request(), to name a few.
- Transfer-Encoding: chunked does not work at the moment and has been disabled.
- At the current time, the ServerResponsewrite stream must be finished before theResponseobject is generated.
The following is an example that reads the URL, method, headers, and body from the request, and writes a response.
import http from '@fastly/http-compute-js';
const server = http.createServer(async (req, res) => {
  // Get URL, method, headers, and body from req
  const url = req.url;
  const method = req.method;
  const headers = {};
  for (let [key, value] of Object.entries(req.headers)) {
    if(!Array.isArray(value)) {
      value = [String(value)];
    }
    headers[key] = value.join(', ');
  }
  let body = null;
  if (method !== 'GET' && method !== 'HEAD') {
    // Reading data out of a stream.Readable 
    body = await new Promise(resolve => {
      const data = [];
      req.on('data', (chunk) => {
        data.push(chunk);
      });
      req.on('end', () => {
        resolve(data.join(''));
      });
    });
  }
  // Write output to res
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    url,
    method,
    headers,
    body,
  }));
});
server.listen();server is an instance of HttpServer, modeled after http.Server. It is created using the createServer() function, usually passing in your request handler. The server begins to listen for fetch events once the listen() function is called.
createServer([onRequest])
- Instantiates an HttpServerinstance, optionally passing in an onRequest listener.
- Parameters:
- onRequest- (optional) supplying this is equivalent to calling- server.on('request', onRequest)after instantiation.
 
- Returns: an HttpServerinstance.
HttpServer class members:
- listen([port][,onListening])- Starts the serverlistening forfetchevents.
- Parameters:
- port- (optional) a port number. This argument is purely for API compatibility with Node's- server.listen(), and is ignored by Compute.
- onListening- (optional) supplying this is equivalent to calling- server.on('listening', onListening)before calling this method.
 
 
- Starts the 
- event: 'listening'- Emitted when the fetchevent handler has been established after callingserver.listen().
 
- Emitted when the 
- event: 'request'- Emitted each time there is a request.
- Parameters:
- request-- http.IncomingMessage
- response-- http.ServerResponse
 
 
Sometimes, you may need to use Node.js-compatible request and response objects for only some parts of your application. Or, you may be working with an existing application or package (for example, "middleware") designed to interact with these objects.
@fastly/http-compute-js provides utility functions that help in this case to help you go back and forth between the Request and Response objects used in Compute and their Node.js-compatible counterparts.
toReqRes(request)
- Converts from a Compute-provided Requestobject to a pair of Node.js-compatible request and response objects.
- Parameters:
- request- A- Requestobject. You would typically obtain this from the- requestproperty of the- eventobject received by your- fetchevent handler.
 
- Returns: an object with the following properties.
- req- An- http.IncomingMessageobject whose- Readableinterface has been wired to the- Requestobject's- body. NOTE: This is an error if the- Request's- bodyhas already been used.
- res- An- http.ServerResponseobject whose- Writableinterface has been wired to an in-memory buffer.
 
toComputeResponse(res)
- Creates a new Responseobject from theresobject above, based on the status code, headers, and body that has been written to it. ThisResponseobject is typically used as the return value from a Computefetchhandler.
- Parameters:
- res- An- http.ServerResponseobject created by- toReqRes().
 
- Returns: a promise that resolves to a Responseobject.
- NOTE: This function returns a Promisethat resolves to aResponseonce theresobject emits the'finish'event, which typically happens when you callres.end(). If your application never signals the end of output, this promise will never resolve, and your application will likely time out.
- If an error occurs, the promise will reject with that error.
The following is an example that shows the use of the manual instantiation functions in a Compute JavaScript application written using a fetch event listener. Node.js-compatible req and res objects are produced from event.request. After having some output written, a Response object is created from the res object and returned from the event listener.
/// <reference types='@fastly/js-compute' />
import { toReqRes, toComputeResponse } from '@fastly/http-compute-js';
addEventListener('fetch', (event) => event.respondWith(handleRequest(event)));
async function handleRequest(event) {
  // Create Node.js-compatible req and res from event.request
  const { req, res } = toReqRes(event.request);
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!'
  }));
  // Create a Compute-at-Edge Response object based on res, and return it
  return await toComputeResponse(res);
}If you encounter any non-security-related bug or unexpected behavior, please file an issue using the bug report template.
Please see our SECURITY.md for guidance on reporting security-related issues.
MIT.
In order for this library to function without requiring a direct dependency on Node.js itself, portions of the code in this library are adapted / copied from Node.js. Those portions are Copyright Joyent, Inc. and other Node.js contributors.
See the LICENSE file for details.