<ApiId extends string, Groups extends HttpApiGroup.Constraint>(
api: HttpApiType.HttpApi<ApiId, Groups>,
client: HttpApiClient.Client<Groups>,
clientId: string
): voidWrap every endpoint on a built HttpApi client with usage metrics and registry hooks.
export const const instrumentEndpoints: <
ApiId extends string,
Groups extends HttpApiGroup.Constraint
>(
api: HttpApiType.HttpApi<ApiId, Groups>,
client: HttpApiClient.Client<Groups>,
clientId: string
) => void
Wrap every endpoint on a built HttpApi client with usage metrics and registry hooks.
instrumentEndpoints = <
function (type parameter) ApiId in <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApiType.HttpApi<ApiId, Groups>, client: HttpApiClient.Client<Groups>, clientId: string): voidApiId extends string,
function (type parameter) Groups in <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApiType.HttpApi<ApiId, Groups>, client: HttpApiClient.Client<Groups>, clientId: string): voidGroups extends import HttpApiGroupHttpApiGroup.Constraint,
>(
api: HttpApi.HttpApi<ApiId, Groups>(parameter) api: {
identifier: Id;
groups: GroupMap<Groups>;
annotations: Context.Context<never>;
add: (...groups: A) => HttpApi.HttpApi<ApiId, Groups | A[number]>;
addHttpApi: (api: HttpApi.HttpApi<Id2, Groups2>) => HttpApi.HttpApi<ApiId, Groups | Groups2>;
prefix: (prefix: Prefix) => HttpApi.HttpApi<ApiId, HttpApiGroup.AddPrefix<Groups, Prefix>>;
middleware: (middleware: Context.Key<I, S>) => HttpApi.HttpApi<ApiId, HttpApiGroup.AddMiddleware<Groups, I>>;
annotate: (tag: Context.Key<I, S>, value: S) => HttpApi.HttpApi<ApiId, Groups>;
annotateMerge: (context: Context.Context<I>) => HttpApi.HttpApi<ApiId, Groups>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
api: import HttpApiTypeHttpApiType.interface HttpApi<out Id extends string, in out Groups extends HttpApiGroup.Constraint = never>An HttpApi is a collection of HTTP API groups and endpoints that represents a
portion of your domain.
When to use
Use when endpoint implementations can be provided with HttpApiBuilder.group, and the
completed API can be registered with HttpApiBuilder.layer.
HttpApi<function (type parameter) ApiId in <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApiType.HttpApi<ApiId, Groups>, client: HttpApiClient.Client<Groups>, clientId: string): voidApiId, function (type parameter) Groups in <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApiType.HttpApi<ApiId, Groups>, client: HttpApiClient.Client<Groups>, clientId: string): voidGroups>,
client: Simplify<
{
readonly [Group in Extract<
Groups,
{
readonly topLevel: false
}
> as HttpApiGroup.Identifier<Group>]: HttpApiClient.Client.GroupByEndpoint<
Group,
never,
never
>
} & HttpApiClient.Client.TopLevelMethods<
Groups,
never,
never
>
>
client: import HttpApiClientHttpApiClient.type Client<Groups extends HttpApiGroup.Constraint, E = never, R = never> = { [K in keyof ({ readonly [Group in Extract<Groups, {
readonly topLevel: false;
}> as HttpApiGroup.Identifier<Group>]: HttpApiClient.Client.GroupByEndpoint<Group, E, R>; } & HttpApiClient.Client.TopLevelMethods<Groups, E, R>)]: ({ readonly [Group in Extract<Groups, {
readonly topLevel: false;
}> as HttpApiGroup.Identifier<Group>]: HttpApiClient.Client.GroupByEndpoint<Group, E, R>; } & HttpApiClient.Client.TopLevelMethods<Groups, E, R>)[K]; } extends infer B ? B : never
The type-safe client shape generated from HTTP API groups, with non-top-level
groups exposed as nested objects and top-level endpoints exposed as methods.
Helper types used to describe generated HTTP API clients, including endpoint
methods, response modes, and grouped client shapes.
Client<function (type parameter) Groups in <ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApiType.HttpApi<ApiId, Groups>, client: HttpApiClient.Client<Groups>, clientId: string): voidGroups>,
clientId: stringclientId: string,
): void => {
const const metrics: {
requests: Metric.Counter<number>
errors: Metric.Counter<number>
duration: Metric.Histogram<number>
}
metrics = const makeEndpointMetrics: (
clientId: string
) => {
requests: Metric.Counter<number>
errors: Metric.Counter<number>
duration: Metric.Histogram<number>
}
makeEndpointMetrics(clientId: stringclientId);
import HttpApiHttpApi.const reflect: <ApiId, Groups>(
self: HttpApi.HttpApi<ApiId, Groups>,
options: {
readonly predicate?:
| Predicate.Predicate<{
readonly endpoint: Top
readonly group: HttpApiGroup.Top
}>
| undefined
readonly onGroup: (options: {
readonly group: HttpApiGroup.Top
readonly mergedAnnotations: Context.Context<never>
}) => void
readonly onEndpoint: (options: {
readonly group: HttpApiGroup.Top
readonly endpoint: Top
readonly mergedAnnotations: Context.Context<never>
readonly middleware: ReadonlySet<AnyService>
readonly successes: ReadonlyMap<
number,
readonly [Top, ...Array<Top>]
>
readonly errors: ReadonlyMap<
number,
readonly [Top, ...Array<Top>]
>
}) => void
}
) => void
Describes the groups and endpoints in an HttpApi.
Details
The callbacks receive each group or endpoint with merged annotations, endpoint
middleware, and response schemas grouped by HTTP status.
reflect(api: HttpApi.HttpApi<ApiId, Groups>(parameter) api: {
identifier: Id;
groups: GroupMap<Groups>;
annotations: Context.Context<never>;
add: (...groups: A) => HttpApi.HttpApi<ApiId, Groups | A[number]>;
addHttpApi: (api: HttpApi.HttpApi<Id2, Groups2>) => HttpApi.HttpApi<ApiId, Groups | Groups2>;
prefix: (prefix: Prefix) => HttpApi.HttpApi<ApiId, HttpApiGroup.AddPrefix<Groups, Prefix>>;
middleware: (middleware: Context.Key<I, S>) => HttpApi.HttpApi<ApiId, HttpApiGroup.AddMiddleware<Groups, I>>;
annotate: (tag: Context.Key<I, S>, value: S) => HttpApi.HttpApi<ApiId, Groups>;
annotateMerge: (context: Context.Context<I>) => HttpApi.HttpApi<ApiId, Groups>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
api, {
onGroup: (options: {
readonly group: HttpApiGroup.Top
readonly mergedAnnotations: Context.Context<never>
}) => void
onGroup: () => {},
onEndpoint: (options: {
readonly group: HttpApiGroup.Top
readonly endpoint: Top
readonly mergedAnnotations: Context.Context<never>
readonly middleware: ReadonlySet<AnyService>
readonly successes: ReadonlyMap<
number,
readonly [Top, ...Array<Top>]
>
readonly errors: ReadonlyMap<
number,
readonly [Top, ...Array<Top>]
>
}) => void
onEndpoint({ group: HttpApiGroup.Top(parameter) group: {
identifier: Id;
key: string;
topLevel: TopLevel;
endpoints: EndpointMap<Endpoints>;
annotations: Context.Context<never>;
add: (...endpoints: A) => HttpApiGroup.HttpApiGroup<string, Top | A[number], boolean>;
prefix: (prefix: Prefix) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>, boolean>;
middleware: (middleware: Context.Key<I, S>) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>, boolean>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotate: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpointsMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpoints: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group, endpoint: Top(parameter) endpoint: {
identifier: Identifier;
path: Path;
method: Method;
params: Schema.Top | undefined;
query: Schema.Top | undefined;
headers: Schema.Top | undefined;
payload: PayloadMap;
success: ReadonlySet<Schema.Top>;
error: ReadonlySet<Schema.Top>;
annotations: Context.Context<never>;
middlewares: ReadonlySet<Context.Key<Middleware, any>>;
prefix: (prefix: Prefix) => HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>;
middleware: (middleware: Context.Key<I, S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>;
annotate: (key: Context.Key<I, S>, value: NoInfer<S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
endpoint }) {
const const bucket:
| Record<string, unknown>
| undefined
bucket: type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<string, unknown> | undefined = group: HttpApiGroup.Top(parameter) group: {
identifier: Id;
key: string;
topLevel: TopLevel;
endpoints: EndpointMap<Endpoints>;
annotations: Context.Context<never>;
add: (...endpoints: A) => HttpApiGroup.HttpApiGroup<string, Top | A[number], boolean>;
prefix: (prefix: Prefix) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>, boolean>;
middleware: (middleware: Context.Key<I, S>) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>, boolean>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotate: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpointsMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpoints: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group.HttpApiGroup<string, Top, boolean>.topLevel: booleantopLevel
? (client: Simplify<
{
readonly [Group in Extract<
Groups,
{
readonly topLevel: false
}
> as HttpApiGroup.Identifier<Group>]: HttpApiClient.Client.GroupByEndpoint<
Group,
never,
never
>
} & HttpApiClient.Client.TopLevelMethods<
Groups,
never,
never
>
>
client as type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<string, unknown>)
: (client: Simplify<
{
readonly [Group in Extract<
Groups,
{
readonly topLevel: false
}
> as HttpApiGroup.Identifier<Group>]: HttpApiClient.Client.GroupByEndpoint<
Group,
never,
never
>
} & HttpApiClient.Client.TopLevelMethods<
Groups,
never,
never
>
>
client as type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<string, type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<string, unknown>>)[group: HttpApiGroup.Top(parameter) group: {
identifier: Id;
key: string;
topLevel: TopLevel;
endpoints: EndpointMap<Endpoints>;
annotations: Context.Context<never>;
add: (...endpoints: A) => HttpApiGroup.HttpApiGroup<string, Top | A[number], boolean>;
prefix: (prefix: Prefix) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>, boolean>;
middleware: (middleware: Context.Key<I, S>) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>, boolean>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotate: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpointsMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpoints: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group.HttpApiGroup<string, Top, boolean>.identifier: stringStable group identifier. This field intentionally is not named name
because HttpApiGroup values can be extended as classes, where name
would collide with JavaScript's built-in Function.name.
identifier];
if (const bucket: Record<string, unknown>bucket === var undefinedundefined) {
return;
}
const const original: unknownoriginal = const bucket: Record<string, unknown>bucket[endpoint: Top(parameter) endpoint: {
identifier: Identifier;
path: Path;
method: Method;
params: Schema.Top | undefined;
query: Schema.Top | undefined;
headers: Schema.Top | undefined;
payload: PayloadMap;
success: ReadonlySet<Schema.Top>;
error: ReadonlySet<Schema.Top>;
annotations: Context.Context<never>;
middlewares: ReadonlySet<Context.Key<Middleware, any>>;
prefix: (prefix: Prefix) => HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>;
middleware: (middleware: Context.Key<I, S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>;
annotate: (key: Context.Key<I, S>, value: NoInfer<S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
endpoint.HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>.identifier: stringidentifier];
if (typeof const original: unknownoriginal !== "function") {
return;
}
const bucket: Record<string, unknown>bucket[endpoint: Top(parameter) endpoint: {
identifier: Identifier;
path: Path;
method: Method;
params: Schema.Top | undefined;
query: Schema.Top | undefined;
headers: Schema.Top | undefined;
payload: PayloadMap;
success: ReadonlySet<Schema.Top>;
error: ReadonlySet<Schema.Top>;
annotations: Context.Context<never>;
middlewares: ReadonlySet<Context.Key<Middleware, any>>;
prefix: (prefix: Prefix) => HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>;
middleware: (middleware: Context.Key<I, S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>;
annotate: (key: Context.Key<I, S>, value: NoInfer<S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
endpoint.HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>.identifier: stringidentifier] = const wrapEndpointCall: <(...args: Array<never>) => Effect.Effect<unknown, unknown, unknown>>(call: (...args: Array<never>) => Effect.Effect<unknown, unknown, unknown>, labels: EndpointLabels, metrics: ReturnType<typeof makeEndpointMetrics>) => (...args: Array<never>) => Effect.Effect<unknown, unknown, unknown>wrapEndpointCall(
const original: Functionoriginal as (...args: never[]args: interface Array<T>Array<never>) => import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<unknown, unknown, unknown>,
{ client: stringclient: clientId: stringclientId, group: stringgroup: group: HttpApiGroup.Top(parameter) group: {
identifier: Id;
key: string;
topLevel: TopLevel;
endpoints: EndpointMap<Endpoints>;
annotations: Context.Context<never>;
add: (...endpoints: A) => HttpApiGroup.HttpApiGroup<string, Top | A[number], boolean>;
prefix: (prefix: Prefix) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>, boolean>;
middleware: (middleware: Context.Key<I, S>) => HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>, boolean>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotate: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpointsMerge: (annotations: Context.Context<I>) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
annotateEndpoints: (key: Context.Key<I, S>, value: S) => HttpApiGroup.HttpApiGroup<string, Top, boolean>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group.HttpApiGroup<string, Top, boolean>.identifier: stringStable group identifier. This field intentionally is not named name
because HttpApiGroup values can be extended as classes, where name
would collide with JavaScript's built-in Function.name.
identifier, endpoint: stringendpoint: endpoint: Top(parameter) endpoint: {
identifier: Identifier;
path: Path;
method: Method;
params: Schema.Top | undefined;
query: Schema.Top | undefined;
headers: Schema.Top | undefined;
payload: PayloadMap;
success: ReadonlySet<Schema.Top>;
error: ReadonlySet<Schema.Top>;
annotations: Context.Context<never>;
middlewares: ReadonlySet<Context.Key<Middleware, any>>;
prefix: (prefix: Prefix) => HttpApiEndpoint<string, HttpMethod, `${Prefix}${string}`, Top, Top, Top, Top, Top, Top, any, unknown>;
middleware: (middleware: Context.Key<I, S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, ApplyServices<I, unknown>>;
annotate: (key: Context.Key<I, S>, value: NoInfer<S>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
annotateMerge: (annotations: Context.Context<I>) => HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
endpoint.HttpApiEndpoint<string, HttpMethod, string, Top, Top, Top, Top, Top, Top, any, unknown>.identifier: stringidentifier },
const metrics: {
requests: Metric.Counter<number>
errors: Metric.Counter<number>
duration: Metric.Histogram<number>
}
metrics,
);
},
});
};