ports-plain-go

command
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package ports-plain-go demonstrates that ports.SourcePort, ports.SinkPort, and ports.ToolPort can be used with ZERO forge/gstream composition — plain idiomatic Go is a first-class consumption style, not a fallback.

The declaration mechanism is IDENTICAL to a forge-pipeline application like examples/sensor-service: declare the port's shape, plug in a ports.RESTPattern to get a typed handle, bind a concrete adapter. Only the code AFTER Bind differs:

// examples/sensor-service (forge-pipeline style):
sensors := domain.SensorReadings.Stream(ctx)
oee := stream.Apply(ctx, sensors, oeeCalcFn, stream.ApplyOptions{})
go domain.OEEResults.Feed(ctx, oee)

// examples/ports-plain-go (plain-Go style, this file):
stream.Drain(ctx, Readings.Stream(ctx), onReading, nil, stream.DrainOptions{})
Alerts.Start(ctx); Alerts.Push(ctx, alert); Alerts.Close()

Three ports, three plain-Go escape hatches:

  • SourcePort[TempReading] — consumed via Stream(ctx) + stream.Drain, never gstream.Apply.
  • ToolPort[ConvertIn, ConvertOut] — business logic registered via SetFunc(func(ctx, In) (Out, error)) AND via SetPipeline, on two endpoints sharing the SAME RESTPattern shape (path param + header param) — proving path/header merge-field codecs behave identically regardless of consumption style.
  • SinkPort[Alert] — driven via Start/Push/Close from a plain goroutine, never Feed(ctx, stream).

Path and header codecs work the same in both consumption styles

ConvertIn's Unit field is merged from the URL path ("/convert/{unit}") and its TraceID field from an optional request header ("X-Trace-Id") — declared once via rest.NewPathParam/rest.NewOptionalHeaderParam on a shared RESTPattern builder (convertPattern). Both the SetFunc endpoint and the SetPipeline endpoint plug in that SAME pattern shape (only the path prefix differs, to run both on one mux); nethttp.PipelineAdapter merges path+header vars into ConvertIn automatically for either one — the merge-field codec layer does not know or care whether the handler behind it is a plain function or a forge-style pipeline.

Two DIFFERENT codecs are in play for "unit", at two DIFFERENT layers: unitCodec validates the segment's runtime VALUE ("c" or "f", checked per request), while exactUnitPathConstraint validates the route TEMPLATE's SHAPE (prefix, exactly one placeholder, nothing after — checked once at Register time via rest.WithPathConstraints on each ToolPort's own rest.Builder). Both reuse the same declare-once idiom this file follows throughout.

Running

go run ./examples/ports-plain-go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL