Servie HTTP Interfaces

4.3.3 · active · verified Tue Apr 21

Servie provides a standard, framework-agnostic set of HTTP interfaces, including `Request`, `Response`, `Body`, `Headers`, and `AbortController`, designed for building interchangeable HTTP clients and servers in both Node.js and browser environments. It aims to offer primitives similar to the Web Fetch API, facilitating universal JavaScript HTTP operations. The current stable version is `4.3.3`, with minor releases frequently addressing bug fixes and introducing small features. Its key differentiators include its dual-environment compatibility without configuration, its focus on raw HTTP interface primitives rather than a full framework, and its modular design which allows it to be used as a foundational layer for various transport mechanisms and middleware libraries.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to create `Request` and `Response` objects, handle various body types (text, JSON), manage headers, and utilize `AbortController` for request cancellation within a simple Servie-compatible request handler.

import { Request, Response, Body, Headers, AbortController } from "servie";

// A simple Servie-compatible request handler
async function handleRequest(request: Request): Promise<Response> {
  const url = new URL(request.url);
  console.log(`Received request for: ${url.pathname} with method ${request.method}`);

  if (url.pathname === "/greet" && request.method === "POST") {
    const name = await request.text();
    const responseBody = `Hello, ${name}!`;
    const headers = new Headers({ "Content-Type": "text/plain" });
    return new Response(responseBody, { status: 200, headers });
  }

  if (url.pathname === "/json" && request.method === "GET") {
    const data = { message: "This is a JSON response", timestamp: new Date().toISOString() };
    const headers = new Headers({ "Content-Type": "application/json" });
    return new Response(JSON.stringify(data), { status: 200, headers });
  }

  if (url.pathname === "/abort-test") {
    const controller = new AbortController();
    const signal = controller.signal;
    setTimeout(() => controller.abort(), 100); // Abort after 100ms
    try {
      await new Promise((resolve, reject) => {
        signal.addEventListener('abort', () => reject(new Error('Request aborted')));
        // Simulate a long operation that could be aborted
        setTimeout(resolve, 500);
      });
      return new Response("Operation completed before abort.", { status: 200 });
    } catch (e: any) {
      if (e.message === 'Request aborted') {
        return new Response("Operation aborted successfully.", { status: 400 });
      }
      throw e;
    }
  }

  return new Response("Not Found", { status: 404 });
}

// Example usage:
async function runExamples() {
  // 1. Simple GET request
  const getRequest = new Request("http://localhost:3000/json", { method: "GET" });
  const getResponse = await handleRequest(getRequest);
  console.log(`GET /json Status: ${getResponse.status}, Body: ${await getResponse.json().then(data => JSON.stringify(data))}`);

  // 2. POST request with a text body
  const postRequest = new Request("http://localhost:3000/greet", {
    method: "POST",
    body: "World",
    headers: { "Content-Type": "text/plain" }
  });
  const postResponse = await handleRequest(postRequest);
  console.log(`POST /greet Status: ${postResponse.status}, Body: ${await postResponse.text()}`);

  // 3. Aborted request demonstration
  const abortRequest = new Request("http://localhost:3000/abort-test", { method: "GET" });
  const abortResponse = await handleRequest(abortRequest);
  console.log(`GET /abort-test Status: ${abortResponse.status}, Body: ${await abortResponse.text()}`);
}

runExamples().catch(console.error);

view raw JSON →