Skip to content

Support customizing low-level (http) transport #11393

@undeadcat

Description

@undeadcat

Which Fern component?

SDK Generator

How important is this?

P2 - Medium (Would be helpful)

What's the feature?

It would be very for useful for an SDK publisher to be able to customize the low-level transport (HttpRequest -> HttpResponse).
From what I've seen, it's not possible easily.
Not sure, maybe this is an intended decision.

Example:
Publisher is a team in a company with many microservices providing an SDK for owned services.
Consumers are multiple other teams in the company.

The use cases could be numerous:

  1. Add tracing to an SDK:
import {context, propagation} from '@opentelemetry/api';

type Transport = (request: HttpRequest) => Promise<HttpResponse>;

declare var defaultTransport: Transport;
const openTelemetryTransport: Transport = async (request: HttpRequest) => {
    propagation.inject(context.active(), request.headers);
    return defaultTransport(request);
}

Related to the tracing use case:

  • Feature request for opentelemetry Support OpenTelemetry #5503
  • For some specific cases (new versions of Node + some versions of fetch + some versions of experimental package https://www.npmjs.com/package/@opentelemetry/instrumentation-http) maybe traces should already be propagated automatically. (In my environment for some reason they weren't: troubleshooting version mismatch). Consider JS as pseudocode here and evaluate the value of a generic extension point that would be applicable to many environments, many languages.
  1. Add metrics collection to a collector that is custom for the company:
const withMetricTransport: Transport = async (request: HttpRequest) => {
    const durationStart = metric.startMeasuring({my_label_1, my_label_2});
    try {
        return await defaultTransport(request);
    } finally {
        durationStart.stopMeasuring();
    }
}

  1. Implement 'Shadow Writes' ('Dual writes') or 'Shadow Reads' ('Read-Through') for service migration
    (Temporarily, with goal to have minimal changes on business service layer).
const myTempServiceMigrationTransport: Transport = async (request: HttpRequest) => {
    const [oldServiceResponse, _unusedDuringMigration] = await Promise.all([
        () => defaultTransport({...request, url: oldServiceUrl}),
        () => defaultTransport({...request, url: newServiceUrl})
    ])
    return oldServiceResponse
}
  1. Implement: 'try multiple service instances, return result from fastest' strategy.

Retries, auth (that are currently supported via specific options) could also be expressed via the same extension point

Any alternatives?

  • (default) Implementing this in service code a layer above the Fern SDK - more changes to business service code, more code to review => higher risk from the point of view of SDK publisher.
  • Monkey-patching techniques: Prototype modification in JS, maybe some class loader or reflection-related in Java

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions