• English
  • Request

    Planned APIs: This page documents the final request-client workflow. commflow@0.0.2 does not export a request runtime; do not use its imports as current production imports. See Current Release Quick Start for runnable exports.

    When To Use It

    request fits one-shot request/response communication:

    ScenarioFit
    Call REST APIsYes
    Call internal HTTP servicesYes
    Centralize timeout / retry / headersYes
    Continuous event streamUse SSE
    Bidirectional realtime messagingUse Socket
    Procedure-style service callsConsider RPC

    Create A Client

    import { createCommflowRequestClient } from 'commflow';
    
    const request = createCommflowRequestClient({
      baseURL: 'https://api.example.com',
      timeout: 5000,
      retry: 2,
      headers: {
        accept: 'application/json'
      }
    });
    OptionUser meaning
    baseURLDefault service URL for relative paths.
    timeoutMaximum wait for one request.
    retryExtra attempts for retryable failures; v1 uses a number.
    headersDefault request headers.

    Send A GET Request

    const response = await request.get('/users/42');
    
    if (!response.ok) {
      return null;
    }
    
    const user = await response.json();

    request keeps fetch()-style semantics by default: HTTP 4xx/5xx is a response, not a transport error. Users should inspect response.ok, status codes, or project helpers for business failure.

    Send A POST Request

    const response = await request.post('/orders', {
      productId: 'p-100',
      quantity: 2
    });
    
    const order = await response.json();

    POST and PATCH should not be retried aggressively by default. PUT and DELETE are often idempotent, but still require business idempotency and server-side guarantees before stronger retry is enabled.

    Body, Query, And Content-Type

    Default request helper rules:

    InputTarget behavior
    request.get('/users?active=1')Keep query in the URL string or URLSearchParams; v1 does not add a dedicated query field.
    request.post('/orders', plainObject)Serialize plain objects as JSON and set content-type: application/json when the user did not set one.
    request.post('/upload', formData)Pass FormData, Blob, ArrayBuffer, ReadableStream, and other BodyInit values through to fetch.
    explicit headers['content-type']User-provided headers win; commflow does not overwrite them.

    Use Targets For Multiple Services

    const request = createCommflowRequestClient({
      targets: [
        {
          name: 'user',
          baseURL: 'https://user.internal',
          timeout: 3000
        },
        {
          name: 'billing',
          baseURL: 'https://billing.internal',
          timeout: 8000,
          retry: 2
        }
      ]
    });
    
    const profile = await request.target('user').get('/profiles/42');
    const invoice = await request.target('billing').get('/invoices/latest');

    Targets let users organize calls by service name instead of scattering service URLs through application code.

    Override One Call

    await request.post('/orders', order, {
      timeout: 10000,
      retry: 0,
      headers: {
        'x-feature': 'checkout'
      }
    });

    Override order:

    SourcePriority
    Per-call optionsHighest
    Target optionsMiddle
    Client defaultsLowest

    If timeout is omitted, commflow adds no timeout at this layer. If retry is omitted, it is 0. The default requestIdHeader is x-request-id.

    Cancellation And Signal

    const controller = new AbortController();
    
    const responsePromise = request.get('/jobs/42', {
      timeout: 3000,
      signal: controller.signal
    });
    
    controller.abort();
    await responsePromise;

    When users pass signal and set timeout, commflow combines them. Whichever fires first cancels the request and throws a structured error with kind: 'aborted' or kind: 'timeout'.

    Provide Request Context

    const request = createCommflowRequestClient({
      contextProvider() {
        return {
          requestId: 'req-123',
          propagatedHeaders: {
            'x-tenant-id': 'tenant-a'
          },
          metadata: {
            source: 'checkout'
          }
        };
      }
    });

    Context is for cross-call data such as requestId, tenant, and trace metadata. Business input should remain explicit in body, query, or headers.

    Use Lifecycle Hooks

    const request = createCommflowRequestClient({
      hooks: {
        beforeRequest(event) {
          event.headers.set('x-request-source', 'commflow');
        },
        afterResponse(event) {
          console.log(event.request.method, event.response.status, event.durationMs);
        },
        onRetry(event) {
          console.warn('retrying request', event.attempt, event.reason);
        },
        onError(event) {
          console.error('request failed', event.error);
        }
      }
    });

    Hooks are for logs, traces, header injection, and diagnostics. They should not hide core business branching. See Configuration for hook boundaries.

    Error Handling

    try {
      const response = await request.get('/users/42');
    
      if (!response.ok) {
        return null;
      }
    
      return await response.json();
    } catch (error) {
      throw error;
    }

    See Errors And Retries for the error model.

    VextJS Relationship

    The VextJS replacement path starts with request: timeout, retry, proxy, request context, and hook behavior currently owned by app.fetch should migrate into commflow request core. See VextJS Integration.