@zio.dev/zio-blocks 0.0.33 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/guides/compile-time-resource-safety-with-scope.md +16 -17
  2. package/guides/getting-started-with-mux.md +1507 -0
  3. package/guides/query-dsl-extending.md +161 -102
  4. package/guides/query-dsl-fluent-builder.md +217 -157
  5. package/guides/query-dsl-reified-optics.md +12 -10
  6. package/guides/query-dsl-sql.md +246 -165
  7. package/guides/telemetry-guide.md +1069 -0
  8. package/guides/zio-schema-migration.md +29 -22
  9. package/index.md +292 -50
  10. package/package.json +1 -1
  11. package/plans/config-follow-up-prs.md +188 -0
  12. package/plans/config-pr-assessment-roadmap.md +310 -0
  13. package/reference/MuxDataFlow.jsx +250 -0
  14. package/reference/async.md +651 -0
  15. package/reference/chunk.md +3533 -308
  16. package/reference/codegen/case-class.md +436 -0
  17. package/reference/codegen/emitter-config.md +383 -0
  18. package/reference/codegen/examples.md +664 -0
  19. package/reference/codegen/field.md +316 -0
  20. package/reference/codegen/index.md +317 -0
  21. package/reference/codegen/scala-emitter.md +392 -0
  22. package/reference/codegen/scala-file.md +276 -0
  23. package/reference/codegen/sealed-trait.md +408 -0
  24. package/reference/codegen/type-definition.md +340 -0
  25. package/reference/codegen/type-ref.md +201 -0
  26. package/reference/combinators.md +347 -117
  27. package/reference/config.md +158 -0
  28. package/reference/context.md +4 -4
  29. package/reference/datastar.md +346 -0
  30. package/reference/docs.md +1461 -345
  31. package/reference/endpoint/auth-type.md +146 -0
  32. package/reference/endpoint/endpoint.md +297 -0
  33. package/reference/endpoint/http-codec.md +249 -0
  34. package/reference/endpoint/index.md +825 -0
  35. package/reference/endpoint/path-codec.md +237 -0
  36. package/reference/endpoint/route-pattern.md +196 -0
  37. package/reference/endpoint/route-tree.md +111 -0
  38. package/reference/endpoint/segment-codec.md +212 -0
  39. package/reference/html.md +1120 -0
  40. package/reference/htmx/attribute-values.md +359 -0
  41. package/reference/htmx/hx-encoding.md +111 -0
  42. package/reference/htmx/hx-params.md +204 -0
  43. package/reference/htmx/hx-swap.md +276 -0
  44. package/reference/htmx/hx-sync.md +251 -0
  45. package/reference/htmx/hx-target.md +314 -0
  46. package/reference/htmx/hx-trigger.md +457 -0
  47. package/reference/htmx/hx-url-update.md +239 -0
  48. package/reference/htmx/index.md +855 -0
  49. package/reference/http-model/index.md +47 -0
  50. package/reference/http-model/model.md +1481 -0
  51. package/reference/http-model/schema.md +747 -0
  52. package/reference/maybe.md +826 -0
  53. package/reference/media-type.md +2 -2
  54. package/reference/mux.mdx +823 -0
  55. package/reference/openapi.md +1351 -0
  56. package/reference/resource-management/defer-handle.md +1 -1
  57. package/reference/resource-management/resource.md +31 -2
  58. package/reference/resource-management/scope.md +28 -12
  59. package/reference/resource-management/wire.md +3 -7
  60. package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
  61. package/reference/ringbuffer/MpscDiagram.jsx +618 -0
  62. package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
  63. package/reference/ringbuffer/SpscDiagram.jsx +677 -0
  64. package/reference/ringbuffer/advanced.mdx +109 -0
  65. package/reference/ringbuffer/index.mdx +145 -0
  66. package/reference/ringbuffer/mpmc.mdx +151 -0
  67. package/reference/ringbuffer/mpsc.mdx +132 -0
  68. package/reference/ringbuffer/spmc.mdx +108 -0
  69. package/reference/ringbuffer/spsc.mdx +344 -0
  70. package/reference/{allows.md → schema/allows.md} +4 -4
  71. package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
  72. package/reference/{binding.md → schema/binding.md} +2 -3
  73. package/reference/schema/built-in-codecs/avro.md +451 -0
  74. package/reference/schema/built-in-codecs/bson.md +480 -0
  75. package/reference/schema/built-in-codecs/csv.md +564 -0
  76. package/reference/schema/built-in-codecs/index.md +77 -0
  77. package/reference/schema/built-in-codecs/json/index.md +295 -0
  78. package/reference/schema/built-in-codecs/json/json-config.md +217 -0
  79. package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
  80. package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
  81. package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
  82. package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
  83. package/reference/schema/built-in-codecs/messagepack.md +508 -0
  84. package/reference/schema/built-in-codecs/thrift.md +433 -0
  85. package/reference/schema/built-in-codecs/toon.md +1078 -0
  86. package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
  87. package/reference/schema/built-in-codecs/yaml.md +552 -0
  88. package/reference/{codec.md → schema/codec.md} +10 -10
  89. package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
  90. package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
  91. package/reference/schema/format.md +92 -0
  92. package/reference/schema/index.md +50 -0
  93. package/reference/schema/migration.md +297 -0
  94. package/reference/{modifier.md → schema/modifier.md} +58 -7
  95. package/reference/{optics.md → schema/optics.md} +2 -2
  96. package/reference/{patch.md → schema/patch.md} +1 -1
  97. package/{path-interpolator.md → reference/schema/path-interpolator.md} +165 -72
  98. package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
  99. package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
  100. package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
  101. package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
  102. package/reference/{schema.md → schema/schema.md} +12 -0
  103. package/reference/{structural-types.md → schema/structural-types.md} +1 -1
  104. package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
  105. package/reference/smithy.md +533 -0
  106. package/reference/sql/db-codec-deriver.md +71 -0
  107. package/reference/sql/db-codec.md +687 -0
  108. package/reference/sql/db-con.md +271 -0
  109. package/reference/sql/db-connection.md +153 -0
  110. package/reference/sql/db-param-writer.md +77 -0
  111. package/reference/sql/db-param.md +66 -0
  112. package/reference/sql/db-result-reader.md +146 -0
  113. package/reference/sql/db-tx.md +82 -0
  114. package/reference/sql/db-value.md +41 -0
  115. package/reference/sql/ddl.md +85 -0
  116. package/reference/sql/frag.md +254 -0
  117. package/reference/sql/index.md +341 -0
  118. package/reference/sql/repo.md +600 -0
  119. package/reference/sql/sql-dialect.md +73 -0
  120. package/reference/sql/sql-logger.md +62 -0
  121. package/reference/sql/sql-name-mapper.md +70 -0
  122. package/reference/sql/table-metadata.md +134 -0
  123. package/reference/sql/table.md +448 -0
  124. package/reference/sql/transactor-zio.md +399 -0
  125. package/reference/sql/transactor.md +353 -0
  126. package/reference/sql-zio.md +112 -0
  127. package/reference/streams/concurrent-operators.md +106 -0
  128. package/reference/streams/index.md +653 -0
  129. package/reference/streams/pipeline.md +718 -0
  130. package/reference/streams/reader.md +1284 -0
  131. package/reference/streams/scala-2-compatibility.md +55 -0
  132. package/reference/streams/sink.md +1426 -0
  133. package/reference/streams/stream.md +2526 -0
  134. package/reference/streams/writer.md +1045 -0
  135. package/reference/streams/zero-boxing.md +275 -0
  136. package/reference/telemetry.md +693 -0
  137. package/reference/typeid.md +5 -19
  138. package/sidebars.js +238 -43
  139. package/reference/formats.md +0 -694
  140. package/reference/http-model.md +0 -1716
  141. package/reference/streams.md +0 -989
  142. package/ringbuffer.md +0 -249
  143. /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
  144. /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
  145. /package/reference/{lazy.md → schema/lazy.md} +0 -0
  146. /package/reference/{reflect.md → schema/reflect.md} +0 -0
  147. /package/reference/{registers.md → schema/registers.md} +0 -0
  148. /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
  149. /package/reference/{syntax.md → schema/syntax.md} +0 -0
  150. /package/reference/{validation.md → schema/validation.md} +0 -0
@@ -0,0 +1,146 @@
1
+ ---
2
+ id: auth-type
3
+ title: "AuthType"
4
+ ---
5
+
6
+ `AuthType` is a sealed trait that describes an HTTP authentication scheme as a first-class type parameter on `Endpoint`. Each `AuthType` variant carries an associated type `ClientRequirement` — the type of credential the client must provide — and a codec that extracts it from the request. Its definition is:
7
+
8
+ ```scala
9
+ sealed trait AuthType {
10
+ type ClientRequirement
11
+ def codec: HttpCodec[CodecKind.Request, ClientRequirement]
12
+ def unauthorizedStatus: Status
13
+ }
14
+ ```
15
+
16
+ ## Motivation
17
+
18
+ Authentication requirements are often encoded informally — a comment in the handler, a middleware convention, or a bare string header check. `AuthType` makes the auth requirement part of the endpoint's static type. A bearer-secured endpoint has type `Endpoint[..., AuthType.Bearer]`, which means:
19
+
20
+ - The `auth.codec` field is typed as `HttpCodec[CodecKind.Request, zio.http.Header.Authorization.Bearer]`, not `HttpCodec[..., String]`.
21
+ - Interpreters (server, client, OpenAPI) can inspect the auth type without stringly-typed reflection.
22
+ - Composing auth types with `|` produces a union that the compiler verifies is discriminated.
23
+
24
+ ## Built-in Variants
25
+
26
+ Each built-in variant maps to a specific HTTP authorization scheme. Use the one that matches your API's authentication model.
27
+
28
+ ### `AuthType.None`
29
+
30
+ The default auth type — no authentication required. Its `ClientRequirement` is `Unit` and its codec is `HttpCodec.Empty`:
31
+
32
+ ```scala
33
+ import zio.blocks.endpoint._
34
+ import zio.blocks.endpoint.RoutePattern._
35
+ import zio.http.Method
36
+
37
+ val publicEndpoint = Endpoint(Method.GET / "health")
38
+ ```
39
+
40
+ ### `AuthType.Basic`
41
+
42
+ HTTP Basic authentication. The `ClientRequirement` is `zio.http.Header.Authorization.Basic`:
43
+
44
+ ```scala
45
+ import zio.blocks.endpoint._
46
+ import zio.blocks.endpoint.RoutePattern._
47
+ import zio.http.Method
48
+
49
+ val basicEndpoint = Endpoint(Method.GET / "admin")
50
+ .auth(AuthType.Basic)
51
+
52
+ val codec = basicEndpoint.auth.codec
53
+ ```
54
+
55
+ ### `AuthType.Bearer`
56
+
57
+ Bearer token authentication (OAuth 2.0 / JWT). The `ClientRequirement` is `zio.http.Header.Authorization.Bearer`:
58
+
59
+ ```scala
60
+ import zio.blocks.endpoint._
61
+ import zio.blocks.endpoint.RoutePattern._
62
+ import zio.http.Method
63
+
64
+ val bearerEndpoint = Endpoint(Method.GET / "me")
65
+ .auth(AuthType.Bearer)
66
+ ```
67
+
68
+ ### `AuthType.Digest`
69
+
70
+ HTTP Digest authentication. The `ClientRequirement` is `zio.http.Header.Authorization.Digest`:
71
+
72
+ ```scala
73
+ import zio.blocks.endpoint._
74
+ import zio.blocks.endpoint.RoutePattern._
75
+ import zio.http.Method
76
+
77
+ val digestEndpoint = Endpoint(Method.GET / "secure")
78
+ .auth(AuthType.Digest)
79
+ ```
80
+
81
+ ### `AuthType.Custom`
82
+
83
+ For authentication schemes not covered by the built-in variants, `Custom` wraps any `HttpCodec[CodecKind.Request, ClientReq]`:
84
+
85
+ ```scala
86
+ import zio.blocks.endpoint._
87
+ import zio.blocks.endpoint.RoutePattern._
88
+ import zio.blocks.schema.Schema
89
+ import zio.http.Method
90
+
91
+ final case class ApiKey(value: String)
92
+
93
+ val apiKeyCodec = HttpCodec.requestHeader("X-Api-Key", Schema.string.transform[ApiKey](ApiKey(_), _.value))
94
+ val apiKeyAuth = AuthType.Custom(apiKeyCodec)
95
+ val keyEndpoint = Endpoint(Method.GET / "data").auth(apiKeyAuth)
96
+ ```
97
+
98
+ ## Composition
99
+
100
+ `AuthType` values compose in two ways: `|` builds an OR alternative that accepts either scheme, and `Scoped` attaches scope requirements to an existing auth type.
101
+
102
+ ### `AuthType#|` — OR composition
103
+
104
+ Two `AuthType` values can be combined with `|` to accept either scheme. The result is an `AuthType.Or` whose `ClientRequirement` is the union of both:
105
+
106
+ ```scala
107
+ import zio.blocks.endpoint._
108
+ import zio.blocks.endpoint.RoutePattern._
109
+ import zio.http.Method
110
+
111
+ val flexEndpoint = Endpoint(Method.GET / "resource")
112
+ .auth(AuthType.Basic | AuthType.Bearer)
113
+ ```
114
+
115
+ The `|` operator automatically computes the combined `ClientRequirement` type as a union of both requirements. The codec of the resulting `Or` is a `HttpCodec.Fallback` — it tries the left scheme first and falls back to the right.
116
+
117
+ ### `AuthType.Scoped`
118
+
119
+ To attach OAuth scope requirements to a bearer auth, wrap it in `AuthType.Scoped`:
120
+
121
+ ```scala
122
+ import zio.blocks.endpoint._
123
+ import zio.blocks.endpoint.RoutePattern._
124
+ import zio.http.Method
125
+
126
+ val scopedEndpoint = Endpoint(Method.GET / "admin")
127
+ .auth(AuthType.Scoped(AuthType.Bearer, List("admin:read", "admin:write")))
128
+ ```
129
+
130
+ `Scoped` does not change the codec — it carries the scopes as metadata for interpreters that perform scope-level authorization checks.
131
+
132
+ ## Unauthorized Status
133
+
134
+ By default, `AuthType` returns `Status.NotFound` when the client does not meet the auth requirement (to avoid leaking endpoint existence). To change this, use `Endpoint#unauthorizedStatus` or call `AuthType#withUnauthorizedStatus` directly:
135
+
136
+ ```scala
137
+ import zio.blocks.endpoint._
138
+ import zio.blocks.endpoint.RoutePattern._
139
+ import zio.http.{Method, Status}
140
+
141
+ val endpoint = Endpoint(Method.GET / "me")
142
+ .auth(AuthType.Bearer)
143
+ .unauthorizedStatus(Status.Unauthorized)
144
+ ```
145
+
146
+ `Or` composition preserves `AuthType#unauthorizedStatus` — it uses the left auth type's status.
@@ -0,0 +1,297 @@
1
+ ---
2
+ id: endpoint
3
+ title: "Endpoint"
4
+ ---
5
+
6
+ `Endpoint[PathInput, Input, Err, Output, Auth]` is the top-level descriptor for an HTTP endpoint. It holds a typed route, three independent codec channels (request input, error output, success output), an authentication type, and documentation metadata. `Endpoint` is pure data — it carries no server or client logic and imposes no effect type. Its full shape is:
7
+
8
+ ```scala
9
+ final case class Endpoint[PathInput, Input, Err, Output, Auth <: AuthType](
10
+ route: RoutePattern[PathInput],
11
+ input: HttpCodec[CodecKind.Request, Input],
12
+ error: HttpCodec[CodecKind.Response, Err],
13
+ output: HttpCodec[CodecKind.Response, Output],
14
+ auth: Auth,
15
+ doc: Doc
16
+ )
17
+ ```
18
+
19
+ ## Motivation
20
+
21
+ An endpoint descriptor separates the **shape** of an HTTP surface from its **execution**. A single `Endpoint` value can be interpreted by a server to generate routes, by a client generator to produce typed API calls, or by an OpenAPI renderer to produce specification documents. This means the endpoint definition is the single source of truth — change it once and every interpreter updates.
22
+
23
+ The five type parameters track everything the compiler needs to enforce consistency across the whole stack:
24
+
25
+ | Parameter | Meaning |
26
+ |-------------|------------------------------------------------------------|
27
+ | `PathInput` | Type of values extracted from path segments |
28
+ | `Input` | Aggregate type of all request inputs (query, header, body) |
29
+ | `Err` | Aggregate type of all error response shapes |
30
+ | `Output` | Aggregate type of all success response shapes |
31
+ | `Auth` | Authentication scheme, carries the client requirement |
32
+
33
+ ## Construction
34
+
35
+ We create an `Endpoint` from a `RoutePattern` using `Endpoint.apply`:
36
+
37
+ ```scala
38
+ import zio.blocks.endpoint._
39
+ import zio.blocks.endpoint.RoutePattern._
40
+ import zio.http.Method
41
+
42
+ val ep = Endpoint(Method.GET / "users" / PathCodec.int("id"))
43
+ ```
44
+
45
+ The route can also be built from a separate `RoutePattern` value:
46
+
47
+ ```scala
48
+ import zio.blocks.endpoint._
49
+ import zio.blocks.endpoint.RoutePattern._
50
+ import zio.http.Method
51
+
52
+ val route = Method.POST / "orders" / PathCodec.uuid("orderId")
53
+ val ep = Endpoint(route)
54
+ ```
55
+
56
+ The initial `Endpoint` starts with `Unit` for all three codec channels and `AuthType.None` for auth, so further builder calls always widen the types additively.
57
+
58
+ ## Request Input Builders
59
+
60
+ Every `Endpoint#in`, `Endpoint#query`, and `Endpoint#header` call adds another input component to the endpoint, widening the `Input` type parameter.
61
+
62
+ ### Body input
63
+
64
+ To add a request body typed by a `Schema`, use `Endpoint#in`:
65
+
66
+ ```scala
67
+ import zio.blocks.endpoint._
68
+ import zio.blocks.endpoint.RoutePattern._
69
+ import zio.blocks.schema.Schema
70
+ import zio.http.Method
71
+
72
+ val ep = Endpoint(Method.POST / "users")
73
+ .in(Schema.string)
74
+ ```
75
+
76
+ To specify the content type explicitly, pass a `MediaType` as well:
77
+
78
+ ```scala
79
+ import zio.blocks.endpoint._
80
+ import zio.blocks.endpoint.RoutePattern._
81
+ import zio.blocks.mediatype.MediaTypes
82
+ import zio.blocks.schema.Schema
83
+ import zio.http.Method
84
+
85
+ val ep = Endpoint(Method.POST / "users")
86
+ .in(MediaTypes.application.`json`, Schema.string)
87
+ ```
88
+
89
+ To add a raw `HttpCodec.Body` node directly, use `Endpoint#in`:
90
+
91
+ ```scala
92
+ import zio.blocks.endpoint._
93
+ import zio.blocks.endpoint.RoutePattern._
94
+ import zio.blocks.schema.Schema
95
+ import zio.http.Method
96
+
97
+ val ep = Endpoint(Method.POST / "users")
98
+ .in(HttpCodec.requestBody(Schema.string))
99
+ ```
100
+
101
+ ### Query parameters
102
+
103
+ To add a query parameter by name and schema, use `Endpoint#query`:
104
+
105
+ ```scala
106
+ import zio.blocks.endpoint._
107
+ import zio.blocks.endpoint.RoutePattern._
108
+ import zio.blocks.schema.Schema
109
+ import zio.http.Method
110
+
111
+ val ep = Endpoint(Method.GET / "users")
112
+ .query("page", Schema.int)
113
+ .query("limit", Schema.int)
114
+ ```
115
+
116
+ To add a pre-built `HttpCodec.Query` node, use `Endpoint#query`:
117
+
118
+ ```scala
119
+ import zio.blocks.endpoint._
120
+ import zio.blocks.endpoint.RoutePattern._
121
+ import zio.blocks.schema.Schema
122
+ import zio.http.Method
123
+
124
+ val pageCodec = HttpCodec.query("page", Schema.int)
125
+ val ep = Endpoint(Method.GET / "users").query(pageCodec)
126
+ ```
127
+
128
+ ### Request headers
129
+
130
+ To add a request header by name and schema, use `Endpoint#header`:
131
+
132
+ ```scala
133
+ import zio.blocks.endpoint._
134
+ import zio.blocks.endpoint.RoutePattern._
135
+ import zio.blocks.schema.Schema
136
+ import zio.http.Method
137
+
138
+ val ep = Endpoint(Method.GET / "users")
139
+ .header("X-Trace-Id", Schema.string)
140
+ ```
141
+
142
+ To add a pre-built `HttpCodec.Header` node, use `Endpoint#header`:
143
+
144
+ ```scala
145
+ import zio.blocks.endpoint._
146
+ import zio.blocks.endpoint.RoutePattern._
147
+ import zio.blocks.schema.Schema
148
+ import zio.http.Method
149
+
150
+ val traceCodec = HttpCodec.requestHeader("X-Trace-Id", Schema.string)
151
+ val ep = Endpoint(Method.GET / "users").header(traceCodec)
152
+ ```
153
+
154
+ ## Success Output Builders
155
+
156
+ Every `Endpoint#out` and `Endpoint#outHeader` call adds a success response alternative or header component, widening `Output`.
157
+
158
+ ### Response body
159
+
160
+ To add a 200 OK response body, use `Endpoint#out`:
161
+
162
+ ```scala
163
+ import zio.blocks.endpoint._
164
+ import zio.blocks.endpoint.RoutePattern._
165
+ import zio.blocks.schema.Schema
166
+ import zio.http.Method
167
+
168
+ val ep = Endpoint(Method.GET / "users")
169
+ .out(Schema.string)
170
+ ```
171
+
172
+ To specify a non-200 status code, use `Endpoint#out` with a `Status`:
173
+
174
+ ```scala
175
+ import zio.blocks.endpoint._
176
+ import zio.blocks.endpoint.RoutePattern._
177
+ import zio.blocks.schema.Schema
178
+ import zio.http.{Method, Status}
179
+
180
+ val ep = Endpoint(Method.POST / "users")
181
+ .out(Status.Created, Schema.int)
182
+ ```
183
+
184
+ To add content-type negotiation, pass a `MediaType`:
185
+
186
+ ```scala
187
+ import zio.blocks.endpoint._
188
+ import zio.blocks.endpoint.RoutePattern._
189
+ import zio.blocks.mediatype.MediaTypes
190
+ import zio.blocks.schema.Schema
191
+ import zio.http.{Method, Status}
192
+
193
+ val ep = Endpoint(Method.GET / "users")
194
+ .out(MediaTypes.application.`json`, Schema.string)
195
+ .out(Status.Created, MediaTypes.text.`plain`, Schema.int)
196
+ ```
197
+
198
+ Multiple `Endpoint#out` calls produce alternatives. The output type widens from `Unit` to the first schema type, then to a nested `Either` for each additional alternative.
199
+
200
+ ### Response headers
201
+
202
+ To add a typed response header, use `Endpoint#outHeader`:
203
+
204
+ ```scala
205
+ import zio.blocks.endpoint._
206
+ import zio.blocks.endpoint.RoutePattern._
207
+ import zio.blocks.schema.Schema
208
+ import zio.http.Method
209
+
210
+ val ep = Endpoint(Method.GET / "users")
211
+ .out(Schema.string)
212
+ .outHeader("X-Total-Count", Schema.int)
213
+ ```
214
+
215
+ ## Error Output Builders
216
+
217
+ Error channels work like success channels but populate the `Err` type parameter. Two variants exist: `Endpoint#outError` (cross-version) and `Endpoint#orOutError` (Scala 3 unions).
218
+
219
+ ### `Endpoint#outError` — cross-version additive errors
220
+
221
+ To add an error response with a status code and body schema, use `Endpoint#outError`:
222
+
223
+ ```scala
224
+ import zio.blocks.endpoint._
225
+ import zio.blocks.endpoint.RoutePattern._
226
+ import zio.blocks.schema.Schema
227
+ import zio.http.{Method, Status}
228
+
229
+ val ep = Endpoint(Method.GET / "users")
230
+ .out(Schema.string)
231
+ .outError(Status.NotFound, Schema.string)
232
+ .outError(Status.BadRequest, Schema.string)
233
+ ```
234
+
235
+ Each `Endpoint#outError` call widens `Err` by one nested `Either` layer.
236
+
237
+ ### `Endpoint#orOutError` — Scala 3 union errors
238
+
239
+ On Scala 3, `Endpoint#orOutError` accumulates error types as a native union type instead of nested `Either`s. The first call replaces the initial `Unit` error outright; subsequent calls build a `Fallback` codec backed by `Unions` derivation:
240
+
241
+ ```scala
242
+ import zio.blocks.endpoint._
243
+ import zio.blocks.endpoint.RoutePattern._
244
+ import zio.blocks.schema.Schema
245
+ import zio.http.{Method, Status}
246
+
247
+ val ep = Endpoint(Method.GET / "users")
248
+ .orOutError(Status.NotFound, Schema.string)
249
+ .orOutError(Status.Conflict, Schema.int)
250
+
251
+ val typed: Endpoint[Unit, Unit, String | Int, Unit, AuthType.None.type] = ep
252
+ ```
253
+
254
+ The compiler rejects overlapping union members — two `Endpoint#orOutError` calls both using `Schema.string` produce a compile error because `String | String` is not a valid discriminated union.
255
+
256
+ ## Authentication
257
+
258
+ To attach an authentication scheme, use `Endpoint#auth`:
259
+
260
+ ```scala
261
+ import zio.blocks.endpoint._
262
+ import zio.blocks.endpoint.RoutePattern._
263
+ import zio.http.Method
264
+
265
+ val secured = Endpoint(Method.GET / "me")
266
+ .auth(AuthType.Bearer)
267
+ ```
268
+
269
+ The `Auth` type parameter carries the `ClientRequirement` associated type, so a bearer-secured endpoint exposes `auth.codec` typed as `HttpCodec[CodecKind.Request, zio.http.Header.Authorization.Bearer]`. See [AuthType](./auth-type.md) for all variants.
270
+
271
+ To override the HTTP status the server sends when the client does not meet the auth requirement, use `Endpoint#unauthorizedStatus`:
272
+
273
+ ```scala
274
+ import zio.blocks.endpoint._
275
+ import zio.blocks.endpoint.RoutePattern._
276
+ import zio.http.{Method, Status}
277
+
278
+ val secured = Endpoint(Method.GET / "me")
279
+ .auth(AuthType.Bearer)
280
+ .unauthorizedStatus(Status.Unauthorized)
281
+ ```
282
+
283
+ ## Documentation
284
+
285
+ To attach a `Doc` value to the endpoint as a whole, use `Endpoint#doc`:
286
+
287
+ ```scala
288
+ import zio.blocks.docs.Doc
289
+ import zio.blocks.endpoint._
290
+ import zio.blocks.endpoint.RoutePattern._
291
+ import zio.http.Method
292
+
293
+ val ep = Endpoint(Method.GET / "users")
294
+ .doc(Doc.empty)
295
+ ```
296
+
297
+ Documentation attached here flows through to OpenAPI generation and any other documentation interpreters.
@@ -0,0 +1,249 @@
1
+ ---
2
+ id: http-codec
3
+ title: "HttpCodec"
4
+ ---
5
+
6
+ `HttpCodec[K, A]` is a composable, typed descriptor for HTTP request and response parts. The phantom type parameter `K` (either `CodecKind.Request` or `CodecKind.Response`) tracks which direction the codec belongs to, so the compiler prevents mixing request-side codecs (query, request header, request body) with response-side codecs (status, response header, response body). The trait signature is:
7
+
8
+ ```scala
9
+ sealed trait HttpCodec[+K <: CodecKind, A]
10
+ ```
11
+
12
+ ## Motivation
13
+
14
+ HTTP surfaces have two directions — request and response — and each direction has several distinct parts. Without static direction tracking, it is easy to accidentally pass a response status codec where a request header codec is expected, or combine a query parameter with a response body.
15
+
16
+ `HttpCodec` makes that class of mistake a compile error. The phantom type `K` carries direction at the type level, so `HttpCodec[CodecKind.Request, A]` and `HttpCodec[CodecKind.Response, A]` are incompatible types. All combinators (`++`, `|`) preserve this constraint: combining two request codecs yields a request codec, and combining request with response is a type error.
17
+
18
+ ## `CodecKind`
19
+
20
+ `CodecKind` is a phantom type hierarchy with two sealed subtypes:
21
+
22
+ ```scala
23
+ sealed trait CodecKind
24
+
25
+ object CodecKind {
26
+ sealed trait Request extends CodecKind // query, request header, request body
27
+ sealed trait Response extends CodecKind // status, response header, response body
28
+ }
29
+ ```
30
+
31
+ These are never instantiated — they exist only to parameterize `HttpCodec[K, A]` at the type level.
32
+
33
+ ## Structure
34
+
35
+ `HttpCodec` is an ADT with seven node types:
36
+
37
+ | Node | Kind | Carries |
38
+ | ------------- | --------- | ---------------------------------------------------- |
39
+ | `Empty` | both | No data — neutral element for `++` |
40
+ | `Combine` | both | Two codecs composed sequentially with `++` |
41
+ | `Fallback` | both | Two codecs composed as alternatives with `&#124;` |
42
+ | `Query` | `Request` | Named query parameter with `Schema[A]` |
43
+ | `Header` | both | Named HTTP header with `Schema[A]` (request or response) |
44
+ | `Body` | both | Request or response body with `Schema[A]` |
45
+ | `StatusCodec` | `Response`| HTTP status code |
46
+
47
+ ## Construction
48
+
49
+ Smart constructors on the `HttpCodec` companion build each atom type. Choose the constructor that matches the HTTP part you are describing.
50
+
51
+ ### Query parameters
52
+
53
+ To describe a named query parameter, use `HttpCodec.query`:
54
+
55
+ ```scala
56
+ import zio.blocks.endpoint._
57
+ import zio.blocks.schema.Schema
58
+
59
+ val limitCodec: HttpCodec.Query[Int] = HttpCodec.query("limit", Schema.int)
60
+ ```
61
+
62
+ Optional fields on `Query` include `default`, `doc`, `examples`, and `deprecated`. To create a query codec with a default value:
63
+
64
+ ```scala
65
+ import zio.blocks.endpoint._
66
+ import zio.blocks.schema.Schema
67
+
68
+ val pageCodec = HttpCodec.query("page", Schema.int, default = Some(1))
69
+ ```
70
+
71
+ ### Request headers
72
+
73
+ To describe a request header by name and schema, use `HttpCodec.requestHeader`:
74
+
75
+ ```scala
76
+ import zio.blocks.endpoint._
77
+ import zio.blocks.schema.Schema
78
+
79
+ val traceHeader: HttpCodec.Header[CodecKind.Request, String] =
80
+ HttpCodec.requestHeader("X-Trace-Id", Schema.string)
81
+ ```
82
+
83
+ To use a zio-http typed header instance (which provides its own name and parse/render logic), pass the typed header directly:
84
+
85
+ ```scala
86
+ import zio.blocks.endpoint._
87
+ import zio.http.Header
88
+
89
+ val authHeader: HttpCodec.Header[CodecKind.Request, Header.Authorization] =
90
+ HttpCodec.requestHeader(Header.Authorization)
91
+ ```
92
+
93
+ ### Response headers
94
+
95
+ To describe a response header, use `HttpCodec.responseHeader`:
96
+
97
+ ```scala
98
+ import zio.blocks.endpoint._
99
+ import zio.blocks.schema.Schema
100
+
101
+ val totalCount: HttpCodec.Header[CodecKind.Response, Int] =
102
+ HttpCodec.responseHeader("X-Total-Count", Schema.int)
103
+ ```
104
+
105
+ ### Request body
106
+
107
+ To describe a request body, use `HttpCodec.requestBody`:
108
+
109
+ ```scala
110
+ import zio.blocks.endpoint._
111
+ import zio.blocks.schema.Schema
112
+
113
+ val body: HttpCodec[CodecKind.Request, String] =
114
+ HttpCodec.requestBody(Schema.string)
115
+ ```
116
+
117
+ To restrict the accepted content types, pass a `Chunk[MediaType]`:
118
+
119
+ ```scala
120
+ import zio.blocks.chunk.Chunk
121
+ import zio.blocks.endpoint._
122
+ import zio.blocks.mediatype.MediaTypes
123
+ import zio.blocks.schema.Schema
124
+
125
+ val jsonBody: HttpCodec[CodecKind.Request, String] =
126
+ HttpCodec.requestBody(Schema.string, mediaTypes = Chunk.single(MediaTypes.application.`json`))
127
+ ```
128
+
129
+ ### Response body
130
+
131
+ To describe a response body, use `HttpCodec.responseBody`:
132
+
133
+ ```scala
134
+ import zio.blocks.endpoint._
135
+ import zio.blocks.schema.Schema
136
+
137
+ val body: HttpCodec[CodecKind.Response, String] =
138
+ HttpCodec.responseBody(Schema.string)
139
+ ```
140
+
141
+ ### Status codes
142
+
143
+ To describe a required HTTP status code, use `HttpCodec.status`:
144
+
145
+ ```scala
146
+ import zio.blocks.endpoint._
147
+ import zio.http.Status
148
+
149
+ val created: HttpCodec[CodecKind.Response, Unit] = HttpCodec.status(Status.Created)
150
+ ```
151
+
152
+ Predefined status constants are available directly on `HttpCodec`:
153
+
154
+ ```scala
155
+ import zio.blocks.endpoint._
156
+
157
+ val ok = HttpCodec.Ok
158
+ val created = HttpCodec.Created
159
+ val notFound = HttpCodec.NotFound
160
+ val badRequest = HttpCodec.BadRequest
161
+ val unauthorized = HttpCodec.Unauthorized
162
+ ```
163
+
164
+ For any other status code, use `HttpCodec.CustomStatus(code)`.
165
+
166
+ ## Composition
167
+
168
+ Two operators combine `HttpCodec` values: `++` sequences parts within the same direction, while `|` creates alternatives for content negotiation or multi-status responses.
169
+
170
+ ### Sequential composition with `++`
171
+
172
+ `++` combines two codecs of the same direction into a single codec whose type is the product of both. The result type is automatically flattened, eliminating `Unit` components and nested tuples:
173
+
174
+ ```scala
175
+ import zio.blocks.endpoint._
176
+ import zio.blocks.schema.Schema
177
+
178
+ val queryAndHeader: HttpCodec[CodecKind.Request, (String, Int)] =
179
+ HttpCodec.query("name", Schema.string) ++ HttpCodec.query("age", Schema.int)
180
+ ```
181
+
182
+ The compiler rejects mixing directions — combining a request codec with a response codec is a type error:
183
+
184
+ ```scala
185
+ import zio.blocks.endpoint._
186
+ import zio.blocks.schema.Schema
187
+ import zio.http.Status
188
+
189
+ // This would be a compile error:
190
+ // HttpCodec.query("name", Schema.string) ++ HttpCodec.status(Status.Ok)
191
+ ```
192
+
193
+ ### Alternative composition with `|`
194
+
195
+ `|` combines two codecs as alternatives. The result type is automatically computed as a nested `Either`:
196
+
197
+ ```scala
198
+ import zio.blocks.endpoint._
199
+ import zio.blocks.schema.Schema
200
+ import zio.http.Status
201
+
202
+ val okOrCreated =
203
+ (HttpCodec.responseBody(Schema.string) ++ HttpCodec.Ok) |
204
+ (HttpCodec.responseBody(Schema.int) ++ HttpCodec.Created)
205
+ ```
206
+
207
+ ## Authentication Codecs
208
+
209
+ Pre-built request codecs for common authorization header schemes are available on `HttpCodec`:
210
+
211
+ ```scala
212
+ import zio.blocks.endpoint._
213
+ import zio.http.Header
214
+
215
+ val basic: HttpCodec[CodecKind.Request, Header.Authorization.Basic] = HttpCodec.basicAuth
216
+ val bearer: HttpCodec[CodecKind.Request, Header.Authorization.Bearer] = HttpCodec.bearerAuth
217
+ val digest: HttpCodec[CodecKind.Request, Header.Authorization.Digest] = HttpCodec.digestAuth
218
+ val proxy: HttpCodec[CodecKind.Request, Header.ProxyAuthorization] = HttpCodec.proxyAuthorization
219
+ ```
220
+
221
+ These codecs use `Schema.transform` internally to parse the raw `Authorization` header string into the typed zio-http auth model, surfacing a `SchemaError` if the scheme does not match.
222
+
223
+ ## Metadata Fields
224
+
225
+ Every atom node (`Query`, `Header`, `Body`, `StatusCodec`) carries optional metadata that documentation renderers and OpenAPI generators consume:
226
+
227
+ | Field | Type | Purpose |
228
+ | ------------ | ----------------- | ---------------------------------------------- |
229
+ | `doc` | `Doc` | Free-text description for OpenAPI output |
230
+ | `examples` | `Chunk[(String, A)]` | Example values for the OpenAPI spec |
231
+ | `deprecated` | `Option[Doc]` | Marks the field as deprecated with a message |
232
+ | `default` | `Option[A]` | Default value (query and header only) |
233
+
234
+ To create a query codec with documentation and an example:
235
+
236
+ ```scala
237
+ import zio.blocks.chunk.Chunk
238
+ import zio.blocks.docs.Doc
239
+ import zio.blocks.endpoint._
240
+ import zio.blocks.schema.Schema
241
+
242
+ val limitCodec = HttpCodec.query(
243
+ name = "limit",
244
+ schema = Schema.int,
245
+ default = Some(20),
246
+ doc = Doc.empty,
247
+ examples = Chunk("default" -> 20, "max" -> 100)
248
+ )
249
+ ```