Skip to content

Optimize type-level performance for unstable HttpApi types#2476

Draft
gcanti wants to merge 2 commits into
mainfrom
http-api-type-perf
Draft

Optimize type-level performance for unstable HttpApi types#2476
gcanti wants to merge 2 commits into
mainfrom
http-api-type-perf

Conversation

@gcanti

@gcanti gcanti commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

New Features

  • Add HttpApiBuilder.Handlers.handleAll, which registers a name-keyed batch of endpoint handlers for a group. Each entry can be either a handler function or { handler, options }, and the object can be supplied in multiple partial batches.
  • HttpApi.groups now preserves the concrete group type for each group name. For example, Api.groups.users is typed as the users group instead of the full group union.
  • HttpApiGroup.endpoints now preserves the concrete endpoint type for each endpoint name. For example, Group.endpoints.getUser is typed as the getUser endpoint instead of the full endpoint union.

Type-Level Performance

Type instantiations for the fluent handler-chain stress test improved as
follows:

endpoints before after
10 32,523 9,054
50 560,763 63,254
100 2,139,063 185,004
500 OOM / SIGKILL 3,319,004

For complete handler registration, the new handleAll API is measured against
the equivalent fluent handle chain on the same endpoint set:

fixture fluent chain handleAll
handlers, 10 eps 9,054 6,675
handlers, 50 eps 63,254 25,395
handlers, 100 eps 185,004 48,795
handlers, 500 eps 3,319,004 235,995
two handler batches, 500 eps 3,319,004 253,657

Breaking Changes

These changes affect unstable HttpApi type-level APIs and structural API,
group, and endpoint types.

Renamed Constraint Types

  • Broad structural constraint exports have been renamed to align with
    Schema.Constraint terminology: HttpApi.Any to HttpApi.Constraint,
    HttpApi.AnyWithProps to HttpApi.ConstraintWithProps, HttpApiGroup.Any to
    HttpApiGroup.Constraint, HttpApiGroup.AnyWithProps to
    HttpApiGroup.ConstraintWithProps, and HttpApiEndpoint.Any to
    HttpApiEndpoint.Constraint.
  • HttpApiEndpoint.AnyWithProps has been replaced by HttpApiEndpoint.Top, whose
    schema parameters are constrained to Schema.Top, including success and error
    schemas.
  • Type guards now expose the renamed constraints: HttpApi.isHttpApi returns
    HttpApi.Constraint, and HttpApiGroup.isHttpApiGroup returns
    HttpApiGroup.Constraint.

API And Group Maps

  • HttpApi.groups is now typed as a name-keyed group map instead of
    ReadonlyRecord<string, Groups>, and HttpApi tracks its group union
    invariantly. Dynamic string indexing must refine the key first or cast to a
    broad runtime record.
  • HttpApiGroup.endpoints is now typed as a name-keyed endpoint map instead of
    ReadonlyRecord<string, Endpoints>, and HttpApiGroup tracks its endpoint
    union invariantly. Dynamic string indexing must refine the key first or cast to
    a broad runtime record.
  • HttpApiGroup.Name now reads the group identifier from
    HttpApiGroup.Constraint; group-like structural types must satisfy that
    lightweight group constraint.

Builder Handler Types

  • HttpApiBuilder.Handlers now tracks endpoints through a name-keyed endpoint map and a set of handled names, instead of tracking the remaining endpoint union. Its public type parameters changed from Handlers<R, Endpoints> to Handlers<R, EndpointsByName, HandledNames>, and its phantom fields changed from _Endpoints to ~EndpointsByName / ~HandledNames.
  • The unused HttpApiBuilder.Handlers.Any helper type has been removed. The internal handler item shape moved from HttpApiBuilder.Handlers.Item to the @internal HttpApiBuilder.HandlerItem export.
  • Duplicate handle / handleRaw registrations for the same endpoint are no longer rejected at the call site. Missing endpoint handlers are still rejected by the final HttpApiBuilder.group return validation.

Client Types

  • HttpApiClient.Client.Group now derives a client from a concrete group type: Client.Group<Group, E, R>. The previous group-union plus group-name form is no longer supported.
  • HttpApiClient.Client.TopLevelMethods now returns a name-keyed method record instead of a union of [name, method] tuples.
  • HttpApiClient.makeWith removes the default HttpClientError.HttpClientError from custom client error types in the returned Client, while preserving any additional custom client errors.

Endpoint Helper Types

  • HttpApiEndpoint.HttpApiEndpoint now stores lightweight phantom metadata for middleware and request shapes: ~Middleware, ~MiddlewareServices, ~Request, and ~RequestRaw. Its type identifier field is now readonly [TypeId]: typeof TypeId.
  • HttpApiEndpoint.Constraint is now a lightweight structural endpoint constraint and does not extend Pipeable; values typed only as HttpApiEndpoint.Constraint do not expose .pipe.
  • Endpoint helper types now read metadata fields directly instead of re-inferring all type parameters from the full HttpApiEndpoint interface. This affects helpers such as Name, Success, Error, Params, Query, Payload, Headers, Middleware, MiddlewareServices, Errors, ErrorServicesEncode, ErrorServicesDecode, Request, RequestRaw, ServerServices, and ClientServices.
  • HttpApiClient.Client.Method and related generated-client helpers now require endpoint types that satisfy HttpApiEndpoint.ConstraintRequest. Endpoint-like structural types must include the lightweight request metadata fields to be accepted.

@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ddb446f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
effect Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gcanti gcanti force-pushed the http-api-type-perf branch from dd52d8f to de6eeca Compare June 24, 2026 06:26
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

File Name Current Size Previous Size Difference
basic.ts 6.58 KB 6.58 KB 0.00 KB (0.00%)
batching.ts 9.09 KB 9.09 KB 0.00 KB (0.00%)
brand.ts 6.14 KB 6.14 KB 0.00 KB (0.00%)
cache.ts 9.79 KB 9.79 KB 0.00 KB (0.00%)
config.ts 18.63 KB 18.63 KB 0.00 KB (0.00%)
differ.ts 16.84 KB 16.84 KB 0.00 KB (0.00%)
http-client.ts 20.40 KB 20.40 KB 0.00 KB (0.00%)
logger.ts 10.13 KB 10.13 KB 0.00 KB (0.00%)
metric.ts 8.42 KB 8.42 KB 0.00 KB (0.00%)
optic.ts 7.35 KB 7.35 KB 0.00 KB (0.00%)
pubsub.ts 13.89 KB 13.89 KB 0.00 KB (0.00%)
queue.ts 10.97 KB 10.97 KB 0.00 KB (0.00%)
schedule.ts 10.17 KB 10.17 KB 0.00 KB (0.00%)
schema-class.ts 17.70 KB 17.70 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 3.49 KB 3.49 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 26.90 KB 26.90 KB 0.00 KB (0.00%)
schema-string-transformation.ts 12.47 KB 12.47 KB 0.00 KB (0.00%)
schema-string.ts 10.18 KB 10.18 KB 0.00 KB (0.00%)
schema-template-literal.ts 14.07 KB 14.07 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 20.50 KB 20.50 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 21.07 KB 21.07 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 17.65 KB 17.65 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 17.55 KB 17.55 KB 0.00 KB (0.00%)
schema-toFormatter.ts 17.41 KB 17.41 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 19.96 KB 19.96 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 17.94 KB 17.94 KB 0.00 KB (0.00%)
schema.ts 16.98 KB 16.98 KB 0.00 KB (0.00%)
stm.ts 11.89 KB 11.89 KB 0.00 KB (0.00%)
stream.ts 9.20 KB 9.20 KB 0.00 KB (0.00%)

@gcanti gcanti changed the title Optimize type-level performance for HttpApiBuilder handler chains Optimize type-level performance for unstable HttpApi types Jun 24, 2026
@gcanti gcanti force-pushed the http-api-type-perf branch 7 times, most recently from c65afa5 to a6a833b Compare July 2, 2026 04:47
@gcanti gcanti force-pushed the http-api-type-perf branch 2 times, most recently from e539529 to 587608b Compare July 3, 2026 17:10
@gcanti gcanti force-pushed the http-api-type-perf branch from 587608b to 80d7900 Compare July 6, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant